Skip to content
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

Add feature sticky header #3580

Merged
Merged
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
4 changes: 3 additions & 1 deletion docs/usage/search-results/layouts/details-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ The 'details list' layout allows you to display items as a structured list, the
| ------- |---------------- | ---------- |
| **Manage columns** | Allows you to build you own table view by adding or removing columns dynamically. For each column, you get the following options:<br><p align="center">[!["Manage columns"](../../../assets/webparts/search-results/layouts/details_list_fields.png)](../../../assets/webparts/search-results/layouts/details_list_fields.png)</p><ul><li>**Sort order**: the order of the column in the table.</li><li>**Column name**: the column friendly name to display.</li><li>**Column value**: you can choose here either a field from the data source current results set (from the list or as free text) without any transformation or use an Handlebars expression by clicking on the checkbox next to it. In this case, all Handlebars helpers from the main template are available and you can also add you own HTML markup in the column value. For HTML fields you can use the special variable `@root.theme` to use theme colors (ex: `@root.theme.palette.themePrimary`).<br>You can specify a different field for sorting when using an Handlebars expression by specifying the field from the separate dropdown.<br>![Handlebars Expression](../../../assets/webparts/search-results/layouts/details_list_hb_expr.png)<br><br>![Handlebars Expression 2](../../../assets/webparts/search-results/layouts/details_list_hb_expr2.png)</li><li>**Minimum width in px**: the minimum width of the column in pixels.</li><li>**Maximum width in px**: the maximum width of the column in pixels.</li><li>**Sortable**: allows you to sort column values according to the **data source sort settings**. It means you must first configure the sort setting at data source level with option _'User sort'_ to `true` to see them in the details list columns configuration. Sort is perfromed one column at a time.</li><li>**Resizable**: allows you to resize the column dynamically in display mode.</li><li>**Multiline**: if the column column should be multiline. By default only ellipsis (...) will be display for larger text.</li></ul>
| **Show file icon** | Hide or display the file icon in the first column.
| **Compact mode** | Display the details list in compact mode.
| **Compact mode** | Display the details list in compact mode.
| **Enable grouping** | Display a grouped list, grouped by the specified column.
| **Enable sticky header** | Display the details list with a sticky header that will stay in place when scrolling. Specify the desired height for the view (in pixels) and then specify the desired items per page in _Number of items per page_ under _Paging options_ and all items on the page will be scrollable within the view.
52 changes: 47 additions & 5 deletions search-parts/src/components/DetailsListComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Fabric, ShimmeredDetailsList, IShimmeredDetailsListProps, Checkbox } from '@fluentui/react';
import { Fabric, ShimmeredDetailsList, IShimmeredDetailsListProps, Sticky, StickyPositionType, Stack, ScrollablePane, ScrollbarVisibility } from '@fluentui/react';
import { ITooltipHostProps, TooltipHost, ITooltipStyles, Shimmer, ShimmerElementsGroup, ShimmerElementType, IShimmerElement, mergeStyleSets, ITheme, Selection } from '@fluentui/react';
import * as Handlebars from 'handlebars';
import { IReadonlyTheme } from '@microsoft/sp-component-base';
Expand Down Expand Up @@ -210,6 +210,16 @@ export interface IDetailsListComponentProps {
* The template service instance
*/
templateService: ITemplateService;

/**
* If the header should be sticky
*/
enableStickyHeader?: boolean;

/**
* The height of the list view when sticky header is enabled
*/
stickyHeaderListViewHeight?: number;
}

export interface IDetailsListComponentState {
Expand All @@ -226,6 +236,16 @@ export class DetailsListComponent extends React.Component<IDetailsListComponentP
private _selection: Selection;
private _selectionMode: SelectionMode = SelectionMode.none;

private _scrollClass = mergeStyleSets({
detailsListWrapper: {
height: this.props.stickyHeaderListViewHeight,
maxHeight: 'inherit',
width: '100%',
position: 'relative'
},
});


constructor(props: IDetailsListComponentProps) {
super(props);

Expand Down Expand Up @@ -432,10 +452,24 @@ export class DetailsListComponent extends React.Component<IDetailsListComponentP
};
}

return (
if (this.props.enableStickyHeader) {
return (
<Fabric>
<ShimmeredDetailsList {...shimmeredDetailsListProps} />
<Stack horizontal className={this._scrollClass.detailsListWrapper}>
<Stack.Item>
<ScrollablePane scrollbarVisibility={ScrollbarVisibility.auto} >
<ShimmeredDetailsList {...shimmeredDetailsListProps} />
</ScrollablePane>
</Stack.Item>
</Stack >
</Fabric>
);
}

return (
<Fabric>
<ShimmeredDetailsList {...shimmeredDetailsListProps} />
</Fabric>
);
}

Expand Down Expand Up @@ -569,7 +603,7 @@ export class DetailsListComponent extends React.Component<IDetailsListComponentP
return <DetailsRow {...rowProps} theme={this.props.themeVariant as ITheme} />;
}

private _onRenderDetailsHeader(props: IDetailsHeaderProps): JSX.Element {
private _onRenderDetailsHeader(props: IDetailsHeaderProps, defaultRender): JSX.Element {

props.onRenderColumnHeaderTooltip = (tooltipHostProps: ITooltipHostProps) => {

Expand All @@ -596,7 +630,15 @@ export class DetailsListComponent extends React.Component<IDetailsListComponentP
return <TooltipHost {...tooltipHostProps} theme={this.props.themeVariant as ITheme} styles={customStyles} />;
};

return <DetailsHeader {...props} theme={this.props.themeVariant as ITheme} />;
if (this.props.enableStickyHeader) {
return (
<Sticky stickyPosition={StickyPositionType.Header} isScrollSynced>
{defaultRender!({...props, theme: this.props.themeVariant as ITheme})}
</Sticky>
);
}

return defaultRender!({...props, theme: this.props.themeVariant as ITheme});
}

private _onColumnClick = (ev: React.MouseEvent<HTMLElement>, column: IColumn): void => {
Expand Down
37 changes: 36 additions & 1 deletion search-parts/src/layouts/results/detailsList/DetailListLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { IPropertyPaneField, PropertyPaneToggle, PropertyPaneDropdown, PropertyP
import { TemplateValueFieldEditor, ITemplateValueFieldEditorProps } from '../../../controls/TemplateValueFieldEditor/TemplateValueFieldEditor';
import { AsyncCombo } from "../../../controls/PropertyPaneAsyncCombo/components/AsyncCombo";
import { IAsyncComboProps } from "../../../controls/PropertyPaneAsyncCombo/components/IAsyncComboProps";
import { PropertyFieldNumber } from "@pnp/spfx-property-controls";

/**
* Details List Builtin Layout
Expand Down Expand Up @@ -47,6 +48,16 @@ export interface IDetailsListLayoutProperties {
* If groups should collapsed by default
*/
groupsCollapsed: boolean;

/**
* If the header should be sticky
*/
enableStickyHeader: boolean;

/**
* The height of the list view when sticky header is enabled
*/
stickyHeaderListViewHeight: number;
}

export class DetailsListLayout extends BaseLayout<IDetailsListLayoutProperties> {
Expand Down Expand Up @@ -303,6 +314,26 @@ export class DetailsListLayout extends BaseLayout<IDetailsListLayoutProperties>
);
}

propertyPaneFields.push(
PropertyPaneToggle('layoutProperties.enableStickyHeader', {
label: strings.Layouts.DetailsList.EnableStickyHeader || 'Enable Sticky Header',
checked: this.properties.enableStickyHeader
}));

//Sticky header options
if (this.properties.enableStickyHeader) {
propertyPaneFields.push(
PropertyFieldNumber('layoutProperties.stickyHeaderListViewHeight', {
label: strings.Layouts.DetailsList.StickyHeaderListViewHeight,
maxValue: 5000,
minValue: 200,
value: this.properties.stickyHeaderListViewHeight ? this.properties.stickyHeaderListViewHeight : 500,
disabled: !this.properties.enableStickyHeader,
key: 'layoutProperties.stickyHeaderListViewHeight',
})
);
}

return propertyPaneFields;
}

Expand All @@ -311,5 +342,9 @@ export class DetailsListLayout extends BaseLayout<IDetailsListLayoutProperties>
if (propertyPath.localeCompare('layoutProperties.enableGrouping') === 0) {
this.properties.groupByField = '';
}
}

if (propertyPath.localeCompare('layoutProperties.enableStickyHeader') === 0) {
this.properties.stickyHeaderListViewHeight = 500;
}
}
}
17 changes: 17 additions & 0 deletions search-parts/src/layouts/results/detailsList/details-list.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
<content id="data-content">

<style>
{{#if properties.layoutProperties.enableStickyHeader}}
.template .ms-DetailsHeader-cell:first-child {
position: sticky;
inset: 0;
background-color: {{@root.theme.palette.primaryBackground}};
z-index: 1;
}

.template .ms-DetailsRow-cell:first-child {
position: sticky;
inset: 0;
background-color: {{@root.theme.palette.primaryBackground}};
z-index: 0;
}
{{/if}}

.template .ms-DetailsRow {
animation-name: none;
Expand Down Expand Up @@ -47,6 +62,8 @@
data-fields="{{JSONstringify @root.properties.dataSourceProperties.sortList}}"
data-default-selected-field="{{sort.selectedSortFieldName}}"
data-default-direction="{{sort.selectedSortDirection}}"
data-enable-sticky-header="{{properties.layoutProperties.enableStickyHeader}}"
data-sticky-header-list-view-height="{{properties.layoutProperties.stickyHeaderListViewHeight}}"
>
</pnp-detailslist>

Expand Down
2 changes: 2 additions & 0 deletions search-parts/src/loc/commonStrings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ declare interface ICommonStrings {
EnableGrouping: string;
CollapsedGroupsByDefault: string;
ResetFieldsBtnLabel: string;
EnableStickyHeader: string;
StickyHeaderListViewHeight: string;
};
Cards: {
Name: string;
Expand Down
4 changes: 3 additions & 1 deletion search-parts/src/loc/da-dk.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ define([], function() {
EnableGrouping: "Aktivér gruppering",
GroupingDescription: "Sørg for, at du har data vist i resultatwebdelen for at få vist en liste over egenskaber.",
CollapsedGroupsByDefault: "Vis collapsed",
ResetFieldsBtnLabel: "Nulstil felter til standardværdier"
ResetFieldsBtnLabel: "Nulstil felter til standardværdier",
EnableStickyHeader: "Aktivér fastgjort header",
StickyHeaderListViewHeight: "Listevisningshøjde (px)"
},
Cards: {
Name: "Cards",
Expand Down
4 changes: 3 additions & 1 deletion search-parts/src/loc/de-de.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ define([], function () {
EnableGrouping: "Gruppierung aktivieren",
GroupingDescription: "Stellen Sie sicher, dass im Ergebnis-Webpart Daten angezeigt werden, damit eine Liste der anzuzeigenden Eigenschaften angezeigt wird.",
CollapsedGroupsByDefault: "Eingeklappt anzeigen",
ResetFieldsBtnLabel: "Felder auf Standardwerte zurücksetzen"
ResetFieldsBtnLabel: "Felder auf Standardwerte zurücksetzen",
EnableStickyHeader: "Fixierte Kopfzeile aktivieren",
StickyHeaderListViewHeight: "Höhe der Listenansicht (px)"
},
Cards: {
Name: "Karten",
Expand Down
4 changes: 3 additions & 1 deletion search-parts/src/loc/en-us.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ define([], function() {
EnableGrouping: "Enable grouping",
GroupingDescription: "Ensure you have data showing in the result web part for a list of properties to show.",
CollapsedGroupsByDefault: "Show collapsed",
ResetFieldsBtnLabel: "Reset fields to default values"
ResetFieldsBtnLabel: "Reset fields to default values",
EnableStickyHeader: "Enable sticky header",
StickyHeaderListViewHeight: "List view height (in px)"
},
Cards: {
Name: "Cards",
Expand Down
4 changes: 3 additions & 1 deletion search-parts/src/loc/es-es.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ define([], function() {
EnableGrouping: "Activar la agrupación",
GroupingDescription: "Asegúrese de tener datos que se muestren en el elemento web de resultados para que se muestre una lista de propiedades.",
CollapsedGroupsByDefault: "Mostrar colapsado",
ResetFieldsBtnLabel: "Restablecer los valores por defecto de los campos"
ResetFieldsBtnLabel: "Restablecer los valores por defecto de los campos",
EnableStickyHeader: "Activar el encabezado fijo",
StickyHeaderListViewHeight: "Altura de la vista de lista con encabezado fijo (en píxeles)"
},
Cards: {
Name: "Tarjetas",
Expand Down
4 changes: 3 additions & 1 deletion search-parts/src/loc/fi-fi.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,9 @@ define([], function() {
EnableGrouping: "Salli ryhmittely",
GroupingDescription: "Varmista, että tulosten verkko-osassa on tietoja, jotta voit näyttää ominaisuusluettelon.",
CollapsedGroupsByDefault: "Näytä ryhmät tiivistettynä",
ResetFieldsBtnLabel: "Palauta kentät templaatin oletusarvoihin"
ResetFieldsBtnLabel: "Palauta kentät templaatin oletusarvoihin",
EnableStickyHeader: "Kiinnitä ylätunniste",
StickyHeaderListViewHeight: "Kiinnitetyn ylätunnisteen korkeus (px)"
},
Cards: {
Name: "Kortit",
Expand Down
4 changes: 3 additions & 1 deletion search-parts/src/loc/fr-fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ define([], function() {
EnableGrouping: "Permettre le regroupement",
GroupingDescription: "Assurez-vous que les données s'affichent dans le composant WebPart de résultat pour obtenir une liste des propriétés à afficher.",
CollapsedGroupsByDefault: "Afficher les groupes réduits",
ResetFieldsBtnLabel: "Rétablir la valeur par défaut dans les champs"
ResetFieldsBtnLabel: "Rétablir la valeur par défaut dans les champs",
EnableStickyHeader: "Activer l’en-tête collant",
StickyHeaderListViewHeight: "Hauteur de la liste de détails (en pixels)"
},
Cards: {
Name: "Cartes",
Expand Down
4 changes: 3 additions & 1 deletion search-parts/src/loc/nb-no.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,9 @@ define([], function () {
EnableGrouping: "Aktiver gruppering",
GroupingDescription: "Sørg for at du har data som vises i resultatwebdelen for å vise en liste over egenskaper.",
CollapsedGroupsByDefault: "Vis kollapsede",
ResetFieldsBtnLabel: "Bruk standardverdiene"
ResetFieldsBtnLabel: "Bruk standardverdiene",
EnableStickyHeader: "Aktiver klebrig overskrift",
StickyHeaderListViewHeight: "Høyde på listevisning med klebrig overskrift (px)"
},
Cards: {
Name: "Kort",
Expand Down
4 changes: 3 additions & 1 deletion search-parts/src/loc/nl-nl.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,9 @@ define([], function() {
EnableGrouping: "Groeperen inschakelen",
GroupingDescription: "Zorg ervoor dat er gegevens worden weergegeven in het resultaatwebonderdeel voor een lijst met eigenschappen die moeten worden weergegeven.",
CollapsedGroupsByDefault: "Toon ingeklapt",
ResetFieldsBtnLabel: "Reset velden naar standaard waarden"
ResetFieldsBtnLabel: "Reset velden naar standaard waarden",
EnableStickyHeader: "Sticky header inschakelen",
StickyHeaderListViewHeight: "Hoogte van de lijstweergave (px)"
},
Cards: {
Name: "Kaarten",
Expand Down
4 changes: 3 additions & 1 deletion search-parts/src/loc/pl-pl.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ define([], function() {
EnableGrouping: "Grupowanie włączone",
GroupingDescription: "Upewnij się, że dane są wyświetlane w wynikowym składniku Web Part, aby wyświetlić listę właściwości.",
CollapsedGroupsByDefault: "Pokaż zapadnięte",
ResetFieldsBtnLabel: "Resetuj pola do wartości domyślnych"
ResetFieldsBtnLabel: "Resetuj pola do wartości domyślnych",
EnableStickyHeader: "Włącz lepką nagłówkę",
StickyListViewHeight: "Wysokość listy ze szczegółami (px)"
},
Cards: {
Name: "Karty",
Expand Down
4 changes: 3 additions & 1 deletion search-parts/src/loc/pt-br.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,9 @@ define([], function() {
EnableGrouping: "Ativar agrupamento",
GroupingDescription: "Certifique-se de que os dados sejam exibidos na Web Part de resultado para uma lista de propriedades a serem exibidas.",
CollapsedGroupsByDefault: "Mostrar recolhido",
ResetFieldsBtnLabel: "Redefinir campos para os valores padrão"
ResetFieldsBtnLabel: "Redefinir campos para os valores padrão",
EnableStickyHeader: "Cabeçalho fixo",
StickyHeaderListViewHeight: "Altura da lista de visualização (px)"
},
Cards: {
Name: "Cartões",
Expand Down
4 changes: 3 additions & 1 deletion search-parts/src/loc/sv-SE.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ define([], function () {
EnableGrouping: "Aktivera gruppering",
GroupingDescription: "Se till att du har data som visas i resultatwebbdelen för en lista över egenskaper att visa.",
CollapsedGroupsByDefault: "Visa kollapsade",
ResetFieldsBtnLabel: "Återställ fält till standardvärden"
ResetFieldsBtnLabel: "Återställ fält till standardvärden",
EnableStickyHeader: "Aktivera fast rubrik",
StickyHeaderListViewHeight: "Höjd för listvy (px)",
},
Cards: {
Name: "Kort",
Expand Down