Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<FluentStack Orientation="Orientation.Vertical" VerticalGap="5">
<div>
<FluentSwitch @bind-Value="enabled" Label="@(enabled ? "Pull is enabled" : "Pull is disabled")" />
<FluentSwitch @bind-Value="direction" Label="@(direction ? "Pull up" : "Pull down")" />
</div>
<FluentPullToRefresh Disabled="@(!enabled)"
Direction="@(direction ? PullDirection.Up : PullDirection.Down)"
OnRefreshAsync="OnRefreshAsync"
Style="width: 100%"
>
<div style="height: 150px; width: 100%; padding: 5px;">
Content to refresh. Pull counter: @counter
</div>
</FluentPullToRefresh>
</FluentStack>

@code {
bool enabled = true;
bool direction;
int counter;

async Task<bool> OnRefreshAsync()
{
counter++;
await Task.Delay(250);
return true;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<FluentPullToRefresh OnRefreshAsync="LoadAsync" TipHeight="40px" Style="overflow-x: auto;">
<PullingTemplate>
Pull to refresh
</PullingTemplate>
<ReleaseTemplate>
Release to update
</ReleaseTemplate>
<CompletedTemplate>
Update completed
</CompletedTemplate>

<ChildContent>
<FluentStack VerticalGap="8px" Padding="12px">
@foreach (var item in items)
{
<FluentCard Padding="@Padding.All2">@item</FluentCard>
}
</FluentStack>
</ChildContent>
</FluentPullToRefresh>

@code {
int counter = 4;
static readonly Random Rand = new();
readonly List<string> items = new()
{
"Item 1",
"Item 2",
"Item 3"
};

async Task<bool> LoadAsync()
{
await Task.Delay(800);
items.Clear();
var count = Rand.Next(1, 6); // random between 1 and 5 inclusive
for (var i = 0; i < count; i++)
{
items.Insert(0, $"New item {counter++}");
}
return true; // indicate more data can still be loaded
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<div class="pull-up-demo">
<FluentPullToRefresh Direction="@PullDirection.Up" OnRefreshAsync="OnRefreshAsync" TipHeight="40px" DragDistance="100" Style="width: 100%">
<LoadingTemplate>
<FluentProgressBar Width="150px"/>
</LoadingTemplate>
<ChildContent>
<div class="pull-content">
@for (int i = 1; i <= count; i++)
{
<span @key="i">item @i</span>
}
</div>
</ChildContent>
</FluentPullToRefresh>
</div>

@code {
int refreshcount = 0;
int count = 3;

async Task<bool> OnRefreshAsync()
{
refreshcount++;
if (count < 15)
{
await Task.Delay(1000);
count += 3;

return true;
}

return false;
}
}

<style>
.pull-up-demo {
height: 51.2vh;
max-width: 400px;
overflow: auto;
}
.pull-content {
user-select: none;
display: flex;
flex-direction: column;
align-items: flex-end;
height: calc(100% - 50px);
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
title: PullToRefresh
route: /PullToRefresh
icon: ArrowSync
---

# PullToRefresh

The Pull-to-refresh is a touchscreen gesture. It involves touching the screen of a computing device with a finger or pressing a button on a pointing device, dragging the screen (downward or upward, depending on the parameters), and then releasing it. This action signals the application to refresh the contents of the component. Its purpose is to make refreshing immediately accessible and to save valuable screen space that would otherwise be occupied by a refresh button.

These features are mainly used on mobile devices. To maintain compatibility with the majority of desktop browsers, an emulator script is included and loaded automatically by the component.

## Default

{{ PullToRefreshDefault }}

## Pull down

With the default settings, the component uses icons for starting and update 'tips'. These can be replaced by using the <code>...Template</code> parameters.
In this example we are using plain text templates. Also the inital tip template is hidden until a pull to refresh action is actually started and hidden once an update is finshed.
The timeout of the update message can be changed.

{{ PullToRefreshDown }}

## Pull up

This demo has a height set for the 'pull up tip'. Also, the distance the tip has to be pulled has been increased.

Instead of using a progress ring, this one shows a progress bar. The maximum number of
items that can be shown is set to 100, so the number of 'pull up's' is limited to 4.

{{ PullToRefreshUp }}

## API

{{ API Type=FluentPullToRefresh }}

10 changes: 9 additions & 1 deletion src/Core/Components/Icons/CoreIcons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ internal static partial class Size20
{
public class Add : Icon { public Add() : base("Add", IconVariant.Regular, IconSize.Size20, "<path d=\"M10 2.5a.5.5 0 0 0-1 0V9H2.5a.5.5 0 0 0 0 1H9v6.5a.5.5 0 0 0 1 0V10h6.5a.5.5 0 0 0 0-1H10V2.5Z\"/>") { } }

public class ArrowCircleDown : Icon { public ArrowCircleDown() : base("ArrowCircleDown", IconVariant.Regular, IconSize.Size20, "<path d=\"M13.3536 10.8536L10.3536 13.8536C10.1583 14.0488 9.84171 14.0488 9.64645 13.8536L6.64645 10.8536C6.45118 10.6583 6.45118 10.3417 6.64645 10.1464C6.84171 9.95118 7.15829 9.95118 7.35355 10.1464L9.5 12.2929L9.5 6.5C9.5 6.22386 9.72386 6 10 6C10.2761 6 10.5 6.22386 10.5 6.5V12.2929L12.6464 10.1464C12.8417 9.95118 13.1583 9.95118 13.3536 10.1464C13.5488 10.3417 13.5488 10.6583 13.3536 10.8536ZM10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18ZM17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10Z\" />") { } }

public class ArrowCircleUp : Icon { public ArrowCircleUp(): base("ArrowCircleUp", IconVariant.Regular, IconSize.Size20, "<path d=\"M6.64645 9.14645L9.64645 6.14645C9.84171 5.95118 10.1583 5.95118 10.3536 6.14645L13.3536 9.14645C13.5488 9.34171 13.5488 9.65829 13.3536 9.85355C13.1583 10.0488 12.8417 10.0488 12.6464 9.85355L10.5 7.70711V13.5C10.5 13.7761 10.2761 14 10 14C9.72386 14 9.5 13.7761 9.5 13.5V7.70711L7.35355 9.85355C7.15829 10.0488 6.84171 10.0488 6.64645 9.85355C6.45118 9.65829 6.45118 9.34171 6.64645 9.14645ZM10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2ZM3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10Z\" />") { } }

public class ArrowReset : Icon { public ArrowReset() : base("ArrowReset", IconVariant.Regular, IconSize.Size20, "<path d=\"M5.85 2.65c.2.2.2.5 0 .7L4.21 5H11a6 6 0 1 1-6 6 .5.5 0 0 1 1 0 5 5 0 1 0 5-5H4.2l1.65 1.65a.5.5 0 1 1-.7.7l-2.5-2.5a.5.5 0 0 1 0-.7l2.5-2.5c.2-.2.5-.2.7 0Z\"/>") { } }

public class ArrowSort : Icon { public ArrowSort() : base("ArrowSort", IconVariant.Regular, IconSize.Size20, "<path d=\"M2.35 7.35 5 4.71V16.5a.5.5 0 0 0 1 0V4.7l2.65 2.65a.5.5 0 0 0 .7-.7l-3.49-3.5A.5.5 0 0 0 5.5 3a.5.5 0 0 0-.39.18L1.65 6.65a.5.5 0 1 0 .7.7Zm15.3 5.3L15 15.29V3.5a.5.5 0 0 0-1 0v11.8l-2.65-2.65a.5.5 0 0 0-.7.7l3.49 3.5a.5.5 0 0 0 .36.15.5.5 0 0 0 .39-.18l3.46-3.47a.5.5 0 1 0-.7-.7Z\"/>") { } }
Expand All @@ -35,11 +39,15 @@ public class ArrowSortDown : Icon { public ArrowSortDown() : base("ArrowSortDown

public class ArrowSortUp : Icon { public ArrowSortUp() : base("ArrowSortUp", IconVariant.Regular, IconSize.Size20, "<path d=\"M9 4.71 6.35 7.35a.5.5 0 1 1-.7-.7L9.1 3.18a.5.5 0 0 1 .74-.03h.01l3.5 3.5a.5.5 0 1 1-.71.7L10 4.71V16.5a.5.5 0 0 1-1 0V4.71Z\"/>") { } }

public class ArrowSyncCircle : Icon { public ArrowSyncCircle() : base("ArrowSyncCircle", IconVariant.Regular, IconSize.Size20, "<path d=\"M10 3C13.866 3 17 6.13401 17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10C3 6.13401 6.13401 3 10 3ZM18 10C18 5.58172 14.4183 2 10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18C14.4183 18 18 14.4183 18 10ZM10.0001 7.5C11.0245 7.5 11.9062 8.11648 12.2922 9H11.4999C11.2237 9 10.9999 9.22386 10.9999 9.5C10.9999 9.77614 11.2237 10 11.4999 10H13.4999C13.776 10 13.9999 9.77614 13.9999 9.5V7.5C13.9999 7.22386 13.776 7 13.4999 7C13.2237 7 12.9999 7.22386 12.9999 7.5V8.19617C12.3877 7.18015 11.2737 6.5 10.0001 6.5C8.96342 6.5 8.03154 6.9513 7.39138 7.66654C7.20721 7.87231 7.22473 8.1884 7.43049 8.37257C7.63625 8.55673 7.95235 8.53922 8.13651 8.33346C8.59499 7.8212 9.25968 7.5 10.0001 7.5ZM7.00012 11.8037V12.5C7.00012 12.7761 6.77626 13 6.50012 13C6.22398 13 6.00012 12.7761 6.00012 12.5V10.5C6.00012 10.2239 6.22398 10 6.50012 10H8.50012C8.77626 10 9.00012 10.2239 9.00012 10.5C9.00012 10.7761 8.77626 11 8.50012 11H7.70793C8.09394 11.8835 8.97557 12.5 10.0001 12.5C10.7404 12.5 11.4051 12.1788 11.8636 11.6665C12.0478 11.4608 12.3639 11.4433 12.5696 11.6274C12.7754 11.8116 12.7929 12.1277 12.6087 12.3335C11.9686 13.0487 11.0367 13.5 10.0001 13.5C8.7263 13.5 7.61231 12.8198 7.00012 11.8037Z\" />") { } }

public class Calendar : Icon { public Calendar() : base("Calendar", IconVariant.Regular, IconSize.Size20, "<path d=\"M7 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2Zm1 2a1 1 0 1 1-2 0 1 1 0 0 1 2 0Zm2-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2Zm1 2a1 1 0 1 1-2 0 1 1 0 0 1 2 0Zm2-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2Zm4-5.5A2.5 2.5 0 0 0 14.5 3h-9A2.5 2.5 0 0 0 3 5.5v9A2.5 2.5 0 0 0 5.5 17h9a2.5 2.5 0 0 0 2.5-2.5v-9ZM4 7h12v7.5c0 .83-.67 1.5-1.5 1.5h-9A1.5 1.5 0 0 1 4 14.5V7Zm1.5-3h9c.83 0 1.5.67 1.5 1.5V6H4v-.5C4 4.67 4.67 4 5.5 4Z\"></path>") { } };

public class CheckboxUnchecked : Icon { public CheckboxUnchecked() : base("CheckboxUnchecked", IconVariant.Regular, IconSize.Size20, "<path d=\"M3 6a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6Zm3-2a2 2 0 0 0-2 2v8c0 1.1.9 2 2 2h8a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6Z\" />") { } }

public class Checkmark : Icon { public Checkmark() : base("Checkmark", IconVariant.Regular, IconSize.Size24, "<path d=\"M4.53 12.97a.75.75 0 0 0-1.06 1.06l4.5 4.5c.3.3.77.3 1.06 0l11-11a.75.75 0 0 0-1.06-1.06L8.5 16.94l-3.97-3.97Z\"/>") { } }
public class Checkmark : Icon { public Checkmark() : base("Checkmark", IconVariant.Regular, IconSize.Size20, "<path d=\"M3.37371 10.1678C3.19025 9.96143 2.87421 9.94284 2.66782 10.1263C2.46143 10.3098 2.44284 10.6258 2.6263 10.8322L6.6263 15.3322C6.81743 15.5472 7.15013 15.557 7.35356 15.3536L17.8536 4.85355C18.0488 4.65829 18.0488 4.34171 17.8536 4.14645C17.6583 3.95118 17.3417 3.95118 17.1465 4.14645L7.02141 14.2715L3.37371 10.1678Z\" />") { } }

public class CheckmarkCircle : Icon { public CheckmarkCircle() : base("CheckMarkCircle", IconVariant.Regular, IconSize.Size20, "<path d=\"M10 2C14.4183 2 18 5.58172 18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2ZM10 3C6.13401 3 3 6.13401 3 10C3 13.866 6.13401 17 10 17C13.866 17 17 13.866 17 10C17 6.13401 13.866 3 10 3ZM13.3584 7.64645C13.532 7.82001 13.5513 8.08944 13.4163 8.28431L13.3584 8.35355L9.35355 12.3584C9.17999 12.532 8.91056 12.5513 8.71569 12.4163L8.64645 12.3584L6.64645 10.3584C6.45118 10.1632 6.45118 9.84658 6.64645 9.65131C6.82001 9.47775 7.08944 9.45846 7.28431 9.59346L7.35355 9.65131L9 11.298L12.6513 7.64645C12.8466 7.45118 13.1632 7.45118 13.3584 7.64645Z\" />") { } }

public class ChevronDown : Icon { public ChevronDown() : base("ChevronDown", IconVariant.Regular, IconSize.Size20, "<path d=\"M15.85 7.65c.2.2.2.5 0 .7l-5.46 5.49a.55.55 0 0 1-.78 0L4.15 8.35a.5.5 0 1 1 .7-.7L10 12.8l5.15-5.16c.2-.2.5-.2.7 0Z\"/>") { } }

Expand Down
26 changes: 26 additions & 0 deletions src/Core/Components/PullToRefresh/FluentPullToRefresh.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@namespace Microsoft.FluentUI.AspNetCore.Components
@inherits FluentComponentBase

<div id="@Id"
class="@ClassValue"
style="@StyleValue"
@attributes="@AdditionalAttributes"
@ontouchstart="@OnTouchStartAsync"
@ontouchmove="@OnTouchMoveAsync"
@ontouchend="@OnTouchEndAsync">
<div style="@WrapperStyle">
@if (Direction == PullDirection.Down && _internalShowStaticTip)
{
<div part="tip" direction="down" style="--fluent-pull-refresh-head-height: @(TipHeight);">
@GetTipContent()
</div>
}
@ChildContent
@if (Direction == PullDirection.Up && _internalShowStaticTip)
{
<div part="tip" direction="up" style="--fluent-pull-refresh-head-height: @(TipHeight);">
@GetTipContent()
</div>
}
</div>
</div>
Loading
Loading