Skip to content

Commit

Permalink
add Blazor support (#198)
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonCropp authored May 26, 2020
1 parent b7c8b3d commit c2ddedc
Show file tree
Hide file tree
Showing 19 changed files with 502 additions and 8 deletions.
67 changes: 65 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ Support is available via a [Tidelift Subscription](https://tidelift.com/subscrip
* [GetTextAsync](#gettextasync)
* [GetText](#gettext)
* [Instance API](#instance-api)
* [Dependency Injection](#dependency-injection)
* [Supported on](#supported-on)
* [Notes on Linux](#notes-on-linux)
* [Blazor WebAssembly](#blazor-webassembly)
* [Linux](#linux)
* [Security contact information](#security-contact-information)<!-- endtoc -->


Expand Down Expand Up @@ -95,6 +97,19 @@ clipboard.SetText("Text to place in clipboard");
<!-- endsnippet -->


### Dependency Injection

An instance of `IClipboard` can be injected into `IServiceCollection`:

<!-- snippet: InjectClipboard -->
<a id='snippet-injectclipboard'/></a>
```cs
serviceCollection.InjectClipboard();
```
<sup><a href='/src/BlazorSample/Program.cs#L16-L18' title='File snippet `injectclipboard` was extracted from'>snippet source</a> | <a href='#snippet-injectclipboard' title='Navigate to start of snippet `injectclipboard`'>anchor</a></sup>
<!-- endsnippet -->


## Supported on

* Windows with .NET Framework 4.6.1 and up
Expand All @@ -107,9 +122,57 @@ clipboard.SetText("Text to place in clipboard");
* Xamarin.Android 9.0 and up
* Xamarin.iOS 10.0 and up
* Universal Windows Platform version 10.0.16299 and up
* Blazor WebAssembly


## Blazor WebAssembly

Due to the dependency on `JSInterop` the static `ClipboardService` is not supported on Blazor.

Instead inhect an `IClipboard`:

<!-- snippet: BlazorStartup -->
<a id='snippet-blazorstartup'/></a>
```cs
var builder = WebAssemblyHostBuilder.CreateDefault();
var serviceCollection = builder.Services;
serviceCollection.InjectClipboard();
builder.RootComponents.Add<App>("app");
```
<sup><a href='/src/BlazorSample/Program.cs#L13-L20' title='File snippet `blazorstartup` was extracted from'>snippet source</a> | <a href='#snippet-blazorstartup' title='Navigate to start of snippet `blazorstartup`'>anchor</a></sup>
<!-- endsnippet -->

Then consume it:

<!-- snippet: Inject -->
<a id='snippet-inject'/></a>
```cs
public partial class IndexModel :
ComponentBase
{
[Inject]
public IClipboard Clipboard { get; set; }

public string Content { get; set; }

public Task CopyTextToClipboard()
{
return Clipboard.SetTextAsync(Content);
}

public async Task ReadTextFromClipboard()
{
Content = await Clipboard.GetTextAsync();
}
}
```
<sup><a href='/src/BlazorSample/Pages/IndexModel.cs#L9-L28' title='File snippet `inject` was extracted from'>snippet source</a> | <a href='#snippet-inject' title='Navigate to start of snippet `inject`'>anchor</a></sup>
<!-- endsnippet -->

Blazor support requires the browser APIs [clipboard.readText](https://caniuse.com/#feat=mdn-api_clipboard_readtext) and [clipboard.writeText](https://caniuse.com/#feat=mdn-api_clipboard_writetext).


## Notes on Linux
## Linux

Linux uses [xclip](https://github.com/astrand/xclip) to access the clipboard. As such it needs to be installed and callable.

Expand Down
25 changes: 24 additions & 1 deletion readme.source.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ In adition to the above static API, there is an instance API exposed:
snippet: SetTextInstance


### Dependency Injection

An instance of `IClipboard` can be injected into `IServiceCollection`:

snippet: InjectClipboard


## Supported on

* Windows with .NET Framework 4.6.1 and up
Expand All @@ -58,9 +65,25 @@ snippet: SetTextInstance
* Xamarin.Android 9.0 and up
* Xamarin.iOS 10.0 and up
* Universal Windows Platform version 10.0.16299 and up
* Blazor WebAssembly


## Blazor WebAssembly

Due to the dependency on `JSInterop` the static `ClipboardService` is not supported on Blazor.

Instead inhect an `IClipboard`:

snippet: BlazorStartup

Then consume it:

snippet: Inject

Blazor support requires the browser APIs [clipboard.readText](https://caniuse.com/#feat=mdn-api_clipboard_readtext) and [clipboard.writeText](https://caniuse.com/#feat=mdn-api_clipboard_writetext).


## Notes on Linux
## Linux

Linux uses [xclip](https://github.com/astrand/xclip) to access the clipboard. As such it needs to be installed and callable.

Expand Down
11 changes: 11 additions & 0 deletions src/BlazorSample/App.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@using BlazorSample.Shared
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
18 changes: 18 additions & 0 deletions src/BlazorSample/BlazorSample.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<RazorLangVersion>3.0</RazorLangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Fody" Version="6.1.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.2.0-preview2.20160.5" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="3.2.0" />
<PackageReference Include="PropertyChanged.Fody" Version="3.2.8" PrivateAssets="all" />
<ProjectReference Include="..\TextCopy\TextCopy.csproj" />
</ItemGroup>

</Project>
3 changes: 3 additions & 0 deletions src/BlazorSample/FodyWeavers.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Weavers GenerateXsd="false">
<PropertyChanged />
</Weavers>
10 changes: 10 additions & 0 deletions src/BlazorSample/Pages/Index.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@page "/"
@inherits IndexModel

<div class="card">
<div class="card-body border-dark">
<input @bind="Content" />
<button type="button" class="btn btn-primary" @onclick="CopyTextToClipboard">Copy</button>
<button type="button" class="btn btn-primary" @onclick="ReadTextFromClipboard">Read</button>
</div>
</div>
29 changes: 29 additions & 0 deletions src/BlazorSample/Pages/IndexModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using PropertyChanged;
using TextCopy;

namespace BlazorSample
{
[AddINotifyPropertyChangedInterface]
#region Inject
public partial class IndexModel :
ComponentBase
{
[Inject]
public IClipboard Clipboard { get; set; }

public string Content { get; set; }

public Task CopyTextToClipboard()
{
return Clipboard.SetTextAsync(Content);
}

public async Task ReadTextFromClipboard()
{
Content = await Clipboard.GetTextAsync();
}
}
#endregion
}
1 change: 1 addition & 0 deletions src/BlazorSample/Pages/_ViewImports.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@layout MainLayout
29 changes: 29 additions & 0 deletions src/BlazorSample/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using BlazorSample;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using TextCopy;

public class Program
{
public static Task Main()
{
#region BlazorStartup
var builder = WebAssemblyHostBuilder.CreateDefault();
var serviceCollection = builder.Services;
#region InjectClipboard
serviceCollection.InjectClipboard();
#endregion
builder.RootComponents.Add<App>("app");
#endregion
serviceCollection.AddTransient(
provider => new HttpClient
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});

return builder.Build().RunAsync();
}
}
6 changes: 6 additions & 0 deletions src/BlazorSample/Shared/MainLayout.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@inherits LayoutComponentBase
<div class="main">
<div class="content px-4">
@Body
</div>
</div>
8 changes: 8 additions & 0 deletions src/BlazorSample/_Imports.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@using System.Net.Http
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using BlazorSample
@using BlazorSample.Shared
@using TextCopy
14 changes: 14 additions & 0 deletions src/BlazorSample/wwwroot/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width">
<base href="/" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" />
<link href="site.css" rel="stylesheet" />
</head>
<body>
<app>Loading...</app>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>
121 changes: 121 additions & 0 deletions src/BlazorSample/wwwroot/site.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

app {
position: relative;
display: flex;
flex-direction: column;
}

.top-row {
height: 3.5rem;
display: flex;
align-items: center;
}

.main {
flex: 1;
}

.main .top-row {
background-color: #e6e6e6;
border-bottom: 1px solid #d6d5d5;
}

.sidebar {
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
}

.sidebar .top-row {
background-color: rgba(0,0,0,0.4);
}

.sidebar .navbar-brand {
font-size: 1.1rem;
}

.sidebar .oi {
width: 2rem;
font-size: 1.1rem;
vertical-align: text-top;
top: -2px;
}

.nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
}

.nav-item:first-of-type {
padding-top: 1rem;
}

.nav-item:last-of-type {
padding-bottom: 1rem;
}

.nav-item a {
color: #d7d7d7;
border-radius: 4px;
height: 3rem;
display: flex;
align-items: center;
line-height: 3rem;
}

.nav-item a.active {
background-color: rgba(255,255,255,0.25);
color: white;
}

.nav-item a:hover {
background-color: rgba(255,255,255,0.1);
color: white;
}

.content {
padding-top: 1.1rem;
}

.navbar-toggler {
background-color: rgba(255, 255, 255, 0.1);
}

@media (max-width: 767.98px) {
.main .top-row {
display: none;
}
}

@media (min-width: 768px) {
app {
flex-direction: row;
}

.sidebar {
width: 250px;
height: 100vh;
position: sticky;
top: 0;
}

.main .top-row {
position: sticky;
top: 0;
}

.main > div {
padding-left: 2rem !important;
padding-right: 1.5rem !important;
}

.navbar-toggler {
display: none;
}

.sidebar .collapse {
/* Never collapse the sidebar for wide screens */
display: block;
}
}
Loading

0 comments on commit c2ddedc

Please sign in to comment.