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
Expand Up @@ -41,6 +41,11 @@
<controls:MarkdownTextBlock x:Name="MarkdownTextBlock2"
Grid.Row="3"
Config="{x:Bind MarkdownConfig, Mode=OneTime}"
Text="{x:Bind Text, Mode=OneTime}" />
Text="{x:Bind Text, Mode=OneTime}"
UseAutoLinks="True"
UseEmphasisExtras="True"
UseListExtras="True"
UsePipeTables="True"
UseTaskLists="True" />
</Grid>
</Page>
170 changes: 170 additions & 0 deletions components/MarkdownTextBlock/src/MarkdownTextBlock.Properties.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Markdig.Syntax;

namespace CommunityToolkit.Labs.WinUI.MarkdownTextBlock;

public partial class MarkdownTextBlock
{
/// <summary>
/// Identifies the <see cref="Config"/> dependency property.
/// </summary>
private static readonly DependencyProperty ConfigProperty = DependencyProperty.Register(
nameof(Config),
typeof(MarkdownConfig),
typeof(MarkdownTextBlock),
new PropertyMetadata(null, OnConfigChanged)
);

/// <summary>
/// Identifies the <see cref="Text"/> dependency property.
/// </summary>
private static readonly DependencyProperty TextProperty = DependencyProperty.Register(
nameof(Text),
typeof(string),
typeof(MarkdownTextBlock),
new PropertyMetadata(null, OnTextChanged));

/// <summary>
/// Identifies the <see cref="UseEmphasisExtras"/> dependency property.
/// </summary>
private static readonly DependencyProperty UseEmphasisExtrasProperty = DependencyProperty.Register(
nameof(UseEmphasisExtras),
typeof(bool),
typeof(MarkdownTextBlock),
new PropertyMetadata(false));

/// <summary>
/// Identifies the <see cref="UsePipeTables"/> dependency property.
/// </summary>
private static readonly DependencyProperty UsePipeTablesProperty = DependencyProperty.Register(
nameof(UsePipeTables),
typeof(bool),
typeof(MarkdownTextBlock),
new PropertyMetadata(false));

/// <summary>
/// Identifies the <see cref="UseListExtras"/> dependency property.
/// </summary>
private static readonly DependencyProperty UseListExtrasProperty = DependencyProperty.Register(
nameof(UseListExtras),
typeof(bool),
typeof(MarkdownTextBlock),
new PropertyMetadata(false));

/// <summary>
/// Identifies the <see cref="UseTaskLists"/> dependency property.
/// </summary>
private static readonly DependencyProperty UseTaskListsProperty = DependencyProperty.Register(
nameof(UseTaskLists),
typeof(bool),
typeof(MarkdownTextBlock),
new PropertyMetadata(false));

/// <summary>
/// Identifies the <see cref="UseAutoLinks"/> dependency property.
/// </summary>
private static readonly DependencyProperty UseAutoLinksProperty = DependencyProperty.Register(
nameof(UseAutoLinks),
typeof(bool),
typeof(MarkdownTextBlock),
new PropertyMetadata(false));

/// <summary>
/// Identifies the <see cref="UseSoftlineBreakAsHardlineBreak"/> dependency property.
/// </summary>
private static readonly DependencyProperty UseSoftlineBreakAsHardlineBreakProperty = DependencyProperty.Register(
nameof(UseSoftlineBreakAsHardlineBreak),
typeof(bool),
typeof(MarkdownTextBlock),
new PropertyMetadata(false));

/// <summary>
/// Identifies the <see cref="MarkdownDocument"/> dependency property.
/// </summary>
private static readonly DependencyProperty MarkdownDocumentProperty = DependencyProperty.Register(
nameof(MarkdownDocument),
typeof(MarkdownDocument),
typeof(MarkdownTextBlock),
new PropertyMetadata(null));

public MarkdownConfig Config
{
get => (MarkdownConfig)GetValue(ConfigProperty);
set => SetValue(ConfigProperty, value);
}

/// <summary>
/// Gets or sets the markdown text to display.
/// </summary>
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}

/// <summary>
/// If true, adds support for strikethroughs, superscript, subscript, inserted, and marked text.
/// </summary>
public bool UseEmphasisExtras
{
get => (bool)GetValue(UseEmphasisExtrasProperty);
set => SetValue(UseEmphasisExtrasProperty, value);
}

/// <summary>
/// If true, adds support for GitHub-style pipe tables.
/// </summary>
public bool UsePipeTables
{
get => (bool)GetValue(UsePipeTablesProperty);
set => SetValue(UsePipeTablesProperty, value);
}

/// <summary>
/// If true, adds support for alphabetic and roman numbering in lists.
/// </summary>
public bool UseListExtras
{
get => (bool)GetValue(UseListExtrasProperty);
set => SetValue(UseListExtrasProperty, value);
}

/// <summary>
/// If true, adds support for GitHub-style task lists using the [ ] and [x] syntax.
/// </summary>
public bool UseTaskLists
{
get => (bool)GetValue(UseTaskListsProperty);
set => SetValue(UseTaskListsProperty, value);
}

/// <summary>
/// If true, parses text that looks like URIs into hyperlinks (e.g. https://...).
/// </summary>
public bool UseAutoLinks
{
get => (bool)GetValue(UseAutoLinksProperty);
set => SetValue(UseAutoLinksProperty, value);
}

/// <summary>
/// If true, considers single newlines as hardline breaks.
/// </summary>
public bool UseSoftlineBreakAsHardlineBreak
{
get => (bool)GetValue(UseSoftlineBreakAsHardlineBreakProperty);
set => SetValue(UseSoftlineBreakAsHardlineBreakProperty, value);
}

/// <summary>
/// Gets the parsed markdown document. May be null if the document has not been parsed yet.
/// </summary>
public MarkdownDocument? MarkdownDocument
{
get => (MarkdownDocument)GetValue(MarkdownDocumentProperty);
private set => SetValue(MarkdownDocumentProperty, value);
}
}
86 changes: 42 additions & 44 deletions components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// See the LICENSE file in the project root for more information.

using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers;
using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers.ObjectRenderers;
using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers.ObjectRenderers.Extensions;
using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers.ObjectRenderers.Inlines;
using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.TextElements;
using Markdig;
using Markdig.Syntax;
Expand All @@ -14,47 +17,10 @@ public partial class MarkdownTextBlock : Control
{
private const string MarkdownContainerName = "MarkdownContainer";
private Grid? _container;
private MarkdownPipeline _pipeline;
private MarkdownPipeline _pipeline = null!;
private MyFlowDocument _document;
private WinUIRenderer? _renderer;

private static readonly DependencyProperty ConfigProperty = DependencyProperty.Register(
nameof(Config),
typeof(MarkdownConfig),
typeof(MarkdownTextBlock),
new PropertyMetadata(null, OnConfigChanged)
);

private static readonly DependencyProperty TextProperty = DependencyProperty.Register(
nameof(Text),
typeof(string),
typeof(MarkdownTextBlock),
new PropertyMetadata(null, OnTextChanged));

private static readonly DependencyProperty MarkdownDocumentProperty = DependencyProperty.Register(
nameof(MarkdownDocument),
typeof(MarkdownDocument),
typeof(MarkdownTextBlock),
new PropertyMetadata(null));

public MarkdownConfig Config
{
get => (MarkdownConfig)GetValue(ConfigProperty);
set => SetValue(ConfigProperty, value);
}

public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}

public MarkdownDocument? MarkdownDocument
{
get => (MarkdownDocument)GetValue(MarkdownDocumentProperty);
private set => SetValue(MarkdownDocumentProperty, value);
}

public event EventHandler<LinkClickedEventArgs>? OnLinkClicked;

internal void RaiseLinkClickedEvent(Uri uri) => OnLinkClicked?.Invoke(this, new LinkClickedEventArgs(uri));
Expand All @@ -79,17 +45,24 @@ public MarkdownTextBlock()
{
this.DefaultStyleKey = typeof(MarkdownTextBlock);
_document = new MyFlowDocument();
_pipeline = new MarkdownPipelineBuilder()
.UseEmphasisExtras()
.UseAutoLinks()
.UseTaskLists()
.UsePipeTables()
.Build();
}

protected override void OnApplyTemplate()
{
base.OnApplyTemplate();

var pipelineBuilder = new MarkdownPipelineBuilder();

// NOTE: Order matters here
if (UseEmphasisExtras) pipelineBuilder = pipelineBuilder.UseEmphasisExtras();
if (UsePipeTables) pipelineBuilder = pipelineBuilder.UsePipeTables();
if (UseListExtras) pipelineBuilder = pipelineBuilder.UseListExtras();
if (UseTaskLists) pipelineBuilder = pipelineBuilder.UseTaskLists();
if (UseAutoLinks) pipelineBuilder = pipelineBuilder.UseAutoLinks();
if (UseSoftlineBreakAsHardlineBreak) pipelineBuilder = pipelineBuilder.UseSoftlineBreakAsHardlineBreak();

_pipeline = pipelineBuilder.Build();

_container = (Grid)GetTemplateChild(MarkdownContainerName);
_container.Children.Clear();
_container.Children.Add(_document.RichTextBlock);
Expand Down Expand Up @@ -128,6 +101,31 @@ private void Build()
if (_renderer == null)
{
_renderer = new WinUIRenderer(_document, Config, this);

// Default block renderers
_renderer.ObjectRenderers.Add(new CodeBlockRenderer());
_renderer.ObjectRenderers.Add(new ListRenderer());
_renderer.ObjectRenderers.Add(new HeadingRenderer());
_renderer.ObjectRenderers.Add(new ParagraphRenderer());
_renderer.ObjectRenderers.Add(new QuoteBlockRenderer());
_renderer.ObjectRenderers.Add(new ThematicBreakRenderer());
_renderer.ObjectRenderers.Add(new HtmlBlockRenderer());

// Default inline renderers
if (UseAutoLinks) _renderer.ObjectRenderers.Add(new AutoLinkInlineRenderer());
_renderer.ObjectRenderers.Add(new CodeInlineRenderer());
_renderer.ObjectRenderers.Add(new DelimiterInlineRenderer());
_renderer.ObjectRenderers.Add(new EmphasisInlineRenderer());
_renderer.ObjectRenderers.Add(new HtmlEntityInlineRenderer());
_renderer.ObjectRenderers.Add(new LineBreakInlineRenderer());
_renderer.ObjectRenderers.Add(new LinkInlineRenderer());
_renderer.ObjectRenderers.Add(new LiteralInlineRenderer());
_renderer.ObjectRenderers.Add(new ContainerInlineRenderer());

// Extension renderers
if (UsePipeTables) _renderer.ObjectRenderers.Add(new TableRenderer());
if (UseTaskLists) _renderer.ObjectRenderers.Add(new TaskListRenderer());
_renderer.ObjectRenderers.Add(new HtmlInlineRenderer());
}
_pipeline.Setup(_renderer);
ApplyText(false);
Expand Down
35 changes: 0 additions & 35 deletions components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@ public WinUIRenderer(MyFlowDocument document, MarkdownConfig config, MarkdownTex
FlowDocument = document;
// set style
_stack.Push(FlowDocument);
LoadOverridenRenderers();
}

private void LoadOverridenRenderers()
{
LoadRenderers();
}

public override object Render(MarkdownObject markdownObject)
Expand All @@ -52,7 +46,6 @@ public void ReloadDocument()
_stack.Clear();
FlowDocument.RichTextBlock.Blocks.Clear();
_stack.Push(FlowDocument);
LoadOverridenRenderers();
}

public void WriteLeafInline(LeafBlock leafBlock)
Expand Down Expand Up @@ -145,32 +138,4 @@ private static void AddInline(IAddChild parent, IAddChild inline)
{
parent.AddChild(inline);
}

protected virtual void LoadRenderers()
{
// Default block renderers
ObjectRenderers.Add(new CodeBlockRenderer());
ObjectRenderers.Add(new ListRenderer());
ObjectRenderers.Add(new HeadingRenderer());
ObjectRenderers.Add(new ParagraphRenderer());
ObjectRenderers.Add(new QuoteBlockRenderer());
ObjectRenderers.Add(new ThematicBreakRenderer());
ObjectRenderers.Add(new HtmlBlockRenderer());

// Default inline renderers
ObjectRenderers.Add(new AutoLinkInlineRenderer());
ObjectRenderers.Add(new CodeInlineRenderer());
ObjectRenderers.Add(new DelimiterInlineRenderer());
ObjectRenderers.Add(new EmphasisInlineRenderer());
ObjectRenderers.Add(new HtmlEntityInlineRenderer());
ObjectRenderers.Add(new LineBreakInlineRenderer());
ObjectRenderers.Add(new LinkInlineRenderer());
ObjectRenderers.Add(new LiteralInlineRenderer());
ObjectRenderers.Add(new ContainerInlineRenderer());

// Extension renderers
ObjectRenderers.Add(new TableRenderer());
ObjectRenderers.Add(new TaskListRenderer());
ObjectRenderers.Add(new HtmlInlineRenderer());
}
}
Loading