Skip to content

Feature/brand center custom font support #651

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
173 changes: 173 additions & 0 deletions docs/documentation/docs/controls/PropertyFieldBrandFontPicker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# PropertyFieldBrandFontPicker control

This control generates a font picker that reads from SharePoint Brand Center and allows users to select corporate-approved fonts for their web parts. It supports both Brand Center fonts, system fonts, and custom font tokens with preview capabilities.

**PropertyFieldBrandFontPicker**

![PropertyFieldBrandFontPicker](../assets/PropertyFieldBrandFontPicker.png)

**PropertyFieldBrandFontPicker with font preview**

![Brand Font Picker with preview](../assets/brandfontpicker-preview.png)

## How to use this control in your solutions

1. Check that you installed the `@pnp/spfx-property-controls` dependency. Check out The [getting started](../../#getting-started) page for more information about installing the dependency.
2. Import the following modules to your component:

```TypeScript
import { PropertyFieldBrandFontPicker } from '@pnp/spfx-property-controls/lib/PropertyFieldBrandFontPicker';
```

3. Create a new property for your web part, for example:

```TypeScript
export interface IPropertyControlsTestWebPartProps {
brandFont: string;
}
```

4. Add the custom property control to the `groupFields` of the web part property pane configuration:

```TypeScript
PropertyFieldBrandFontPicker('brandFont', {
label: 'Brand Font',
initialValue: this.properties.brandFont,
onSelectionChanged: (fontToken) => {
this.properties.brandFont = fontToken.value;
this.onPropertyPaneFieldChanged('brandFont', fontToken.value);
},
context: this.context,
showPreview: true,
key: 'brandFontFieldId'
})
```

## Using Custom Font Tokens

You can provide your own list of font tokens instead of relying on Brand Center:

```TypeScript
import { IBrandFontToken } from '@pnp/spfx-property-controls/lib/PropertyFieldBrandFontPicker';

const customFontTokens: IBrandFontToken[] = [
{
name: 'corporateHeading',
displayName: 'Corporate Heading Font',
value: '"Montserrat", sans-serif',
category: 'custom'
},
{
name: 'corporateBody',
displayName: 'Corporate Body Font',
value: '"Open Sans", sans-serif',
category: 'custom'
}
];

PropertyFieldBrandFontPicker('brandFont', {
label: 'Custom Brand Font',
initialValue: this.properties.brandFont,
onSelectionChanged: (fontToken) => {
this.properties.brandFont = fontToken.value;
this.onPropertyPaneFieldChanged('brandFont', fontToken.value);
},
context: this.context,
customFontTokens: customFontTokens,
showPreview: true,
key: 'brandFontFieldId'
})
```

## Implementation

The `PropertyFieldBrandFontPicker` control can be configured with the following properties:

| Property | Type | Required | Description |
| ---- | ---- | ---- | ---- |
| label | string | no | Property field label displayed on top. |
| initialValue | string | no | Initial font value to be selected. |
| onSelectionChanged | function | yes | Callback function when a font is selected. Returns the selected IBrandFontToken. |
| context | BaseComponentContext | yes | The SPFx component context. |
| customFontTokens | IBrandFontToken[] | no | Array of custom font tokens to display instead of Brand Center fonts. |
| showPreview | boolean | no | Whether to display font preview text in the dropdown. Default is true. |
| disabled | boolean | no | Whether the control is disabled. Default is false. |
| onFontTokensLoaded | function | no | Callback function called when font tokens are loaded. |
| loadingErrorMessage | string | no | Custom error message to display when font loading fails. |
| key | string | yes | An UNIQUE key indicates the identity of this control. |

Interface `IBrandFontToken`:

| Property | Type | Required | Description |
| ---- | ---- | ---- | ---- |
| name | string | yes | Unique identifier for the font token. |
| displayName | string | yes | Display name shown in the dropdown. |
| value | string | yes | CSS font-family value (e.g., '"Lato", sans-serif'). |
| preview | string | no | Optional preview text. |
| category | string | no | Category for grouping (e.g., 'site', 'microsoft', 'custom'). |
| fileUrl | string | no | Optional URL to font file or CSS. |

## Example

```TypeScript
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';

import { PropertyFieldBrandFontPicker } from '@pnp/spfx-property-controls/lib/PropertyFieldBrandFontPicker';

export interface IPropertyControlsTestWebPartProps {
brandFont: string;
}

export default class PropertyControlsTestWebPart extends BaseClientSideWebPart<IPropertyControlsTestWebPartProps> {

public render(): void {
const element: React.ReactElement<IPropertyControlsTestWebPartProps> = React.createElement(
PropertyControlsTest,
{
brandFont: this.properties.brandFont
}
);

ReactDom.render(element, this.domElement);
}

protected get propertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyFieldBrandFontPicker('brandFont', {
label: 'Brand Font',
initialValue: this.properties.brandFont,
onSelectionChanged: (fontToken) => {
this.properties.brandFont = fontToken.value;
this.onPropertyPaneFieldChanged('brandFont', fontToken.value);
},
context: this.context,
showPreview: true,
key: 'brandFontFieldId'
})
]
}
]
}
]
};
}
}
```

![](https://telemetry.sharepointpnp.com/sp-dev-fx-property-controls/wiki/PropertyFieldBrandFontPicker)
1 change: 1 addition & 0 deletions docs/documentation/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ telemetry.optOut();
The following controls are currently available:

- [PropertyFieldButton](./controls/PropertyFieldButton) (Property pane Button)
- [PropertyFieldBrandFontPicker](./controls/PropertyFieldBrandFontPicker) (Property pane Brand Center font selector)
- [PropertyFieldCodeEditor](./controls/PropertyFieldCodeEditor) (Property pane code editor)
- [PropertyFieldCollectionData](./controls/PropertyFieldCollectionData) (Property pane collection data editor)
- [PropertyFieldColorPicker](./controls/PropertyFieldColorPicker) (Property pane color picker)
Expand Down
1 change: 1 addition & 0 deletions src/PropertyFieldBrandFontPicker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './propertyFields/brandFontPicker';
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export * from './PropertyFieldEnterpriseTermPicker';
export * from './PropertyFieldMultiSelect';
export * from './PropertyFieldNumber';
export * from './PropertyFieldGuid';
export * from './PropertyFieldBrandFontPicker';

export * from './PropertyFieldButtonWithCallout';
export * from './PropertyFieldCheckboxWithCallout';
Expand Down
137 changes: 137 additions & 0 deletions src/propertyFields/brandFontPicker/IPropertyFieldBrandFontPicker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-property-pane';
import { BaseComponentContext } from '@microsoft/sp-component-base';

/**
* Brand font token interface
*/
export interface IBrandFontToken {
/**
* The CSS variable name (e.g., "fontFamilyBase")
*/
name: string;

/**
* The display name for the font
*/
displayName: string;

/**
* The font family value (e.g., "Segoe UI, system-ui, sans-serif")
*/
value: string;

/**
* Optional preview text
*/
preview?: string;

/**
* Optional font file URL
*/
fileUrl?: string;

/**
* Font source category
*/
category?: 'site' | 'organization' | 'microsoft';
}

/**
* Public properties of the PropertyFieldBrandFontPicker custom field
*/
export interface IPropertyFieldBrandFontPickerProps {
/**
* Property field label displayed on top
*/
label: string;

/**
* Defines an onPropertyChange function to raise when the selected value changes.
* Normally this function must be defined with the 'this.onPropertyChange'
* method of the web part object.
*/
onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void; // eslint-disable-line @typescript-eslint/no-explicit-any

/**
* The initial selected font token name
*/
initialValue?: string;

/**
* Whether the property pane field is enabled or not
*/
disabled?: boolean;

/**
* The context object of the SPFx component
*/
context: BaseComponentContext;

/**
* Custom properties object
*/
properties?: any; // eslint-disable-line @typescript-eslint/no-explicit-any

/**
* An unique key that indicates the identity of this control
*/
key?: string;

/**
* Whether the property pane field is visible or not
*/
isHidden?: boolean;

/**
* Custom font tokens to use as fallback or override
*/
customFontTokens?: IBrandFontToken[];

/**
* Callback function that will be called on font tokens loaded
*/
onFontTokensLoaded?: (tokens: IBrandFontToken[]) => void;

/**
* Whether to show preview text in the dropdown
*/
showPreview?: boolean;

/**
* Custom preview text to use
*/
previewText?: string;

/**
* Error message to display when font tokens cannot be loaded
*/
loadingErrorMessage?: string;

/**
* Whether to use system fonts as fallback when Brand Center is not available
*/
useSystemFallback?: boolean;
}

/**
* Private properties of the PropertyFieldBrandFontPicker custom field.
* We separate public & private properties to include onRender & onDispose method waited
* by the PropertyPane control without asking it from the developer
*/
export interface IPropertyFieldBrandFontPickerPropsInternal extends IPropertyPaneCustomFieldProps {
label: string;
initialValue?: string;
targetProperty: string;
context: BaseComponentContext;
onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void; // eslint-disable-line @typescript-eslint/no-explicit-any
properties: any; // eslint-disable-line @typescript-eslint/no-explicit-any
disabled?: boolean;
key: string;
isHidden?: boolean;
customFontTokens?: IBrandFontToken[];
onFontTokensLoaded?: (tokens: IBrandFontToken[]) => void;
showPreview?: boolean;
previewText?: string;
loadingErrorMessage?: string;
useSystemFallback?: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { IBrandFontToken } from './IPropertyFieldBrandFontPicker';
import { BaseComponentContext } from '@microsoft/sp-component-base';

/**
* PropertyFieldBrandFontPickerHost properties interface
*/
export interface IPropertyFieldBrandFontPickerHostProps {
label: string;
initialValue?: string;
targetProperty: string;
context: BaseComponentContext;
onSelectionChanged?: (option: IBrandFontToken) => void;
disabled?: boolean;
customFontTokens?: IBrandFontToken[];
onFontTokensLoaded?: (tokens: IBrandFontToken[]) => void;
showPreview?: boolean;
previewText?: string;
loadingErrorMessage?: string;
useSystemFallback?: boolean;
}

/**
* PropertyFieldBrandFontPickerHost state interface
*/
export interface IPropertyFieldBrandFontPickerHostState {
loading: boolean;
fontTokens: IBrandFontToken[];
selectedToken?: IBrandFontToken;
errorMessage?: string;
}
Loading