diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c51dbcb26..1cc92604e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -257,9 +257,19 @@ jobs: with: vs-version: '[17.9,)' + - name: Define excluded MultiTargets (WinUI 2) + if: ${{ matrix.winui == '2' }} + run: | + echo "EXCLUDED_MULTITARGETS=wasdk" >> $env:GITHUB_ENV + + - name: Define excluded MultiTargets (WinUI 3) + if: ${{ matrix.winui == '3' }} + run: | + echo "EXCLUDED_MULTITARGETS=uwp" >> $env:GITHUB_ENV + # Build and pack component nupkg - name: Build and pack component packages - run: ./tooling/Build-Toolkit-Components.ps1 -MultiTargets all -WinUIMajorVersion ${{ matrix.winui }} -DateForVersion ${{ env.VERSION_DATE }} ${{ env.VERSION_PROPERTY != '' && format('-PreviewVersion "{0}"', env.VERSION_PROPERTY) || '' }} ${{ env.ENABLE_DIAGNOSTICS == 'true' && '-EnableBinlogs' || '' }} ${{ env.ENABLE_DIAGNOSTICS == 'true' && '-Verbose' || '' }} -BinlogOutput ./ -NupkgOutput ./ -Release + run: ./tooling/Build-Toolkit-Components.ps1 -MultiTargets all -ExcludeMultiTargets ${{ env.EXCLUDED_MULTITARGETS }} -WinUIMajorVersion ${{ matrix.winui }} -DateForVersion ${{ env.VERSION_DATE }} ${{ env.VERSION_PROPERTY != '' && format('-PreviewVersion "{0}"', env.VERSION_PROPERTY) || '' }} ${{ env.ENABLE_DIAGNOSTICS == 'true' && '-EnableBinlogs' || '' }} ${{ env.ENABLE_DIAGNOSTICS == 'true' && '-Verbose' || '' }} -BinlogOutput ./ -NupkgOutput ./ -Release - name: Validate package names if: ${{ env.VERSION_PROPERTY != '' }} diff --git a/Directory.Build.props b/Directory.Build.props index 74436b013..72e05671d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,10 @@ true true - $(NoWarn);Uno0001 + $(NoWarn);Uno0001 + + + NU1901;NU1902;NU1903;NU1904 diff --git a/ReadMe.md b/ReadMe.md index 7aa2894a4..1bf966208 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -21,6 +21,22 @@ If you find an experiment useful, please up-vote 👍 its corresponding issue an Otherwise, you can clone the repo, open the `components` directory, navigate within the folder for a particular experiment and open up it's solution file in Visual Studio. Run one of the project heads (_ExperimentName.Uwp/Wasm/WinAppSDK_) to see its samples. +**List of current experiments** +- [AppServices](https://github.com/CommunityToolkit/Labs-Windows/tree/main/components/AppServices) +- [CanvasLayout](https://github.com/CommunityToolkit/Labs-Windows/blob/main/components/CanvasLayout/samples/CanvasLayout.md) +- [CanvasView](https://github.com/CommunityToolkit/Labs-Windows/blob/main/components/CanvasView/samples/CanvasView.md) +- [DataTable](https://github.com/CommunityToolkit/Labs-Windows/blob/main/components/DataTable/samples/DataTable.md) +- [Extensions.DependencyInjection](https://github.com/CommunityToolkit/Labs-Windows/tree/main/components/Extensions.DependencyInjection) +- [MarkdownTextBlock](https://github.com/CommunityToolkit/Labs-Windows/blob/main/components/MarkdownTextBlock/samples/MarkdownTextBlock.md) +- [MarqueeText](https://github.com/CommunityToolkit/Labs-Windows/blob/main/components/MarqueeText/samples/MarqueeText.md) +- [Notifications](https://github.com/CommunityToolkit/Labs-Windows/tree/main/components/Notifications) +- [Ribbon](https://github.com/CommunityToolkit/Labs-Windows/blob/main/components/Ribbon/samples/Ribbon.md) +- [RivePlayer](https://github.com/CommunityToolkit/Labs-Windows/blob/main/components/RivePlayer/samples/RivePlayer.md) +- [Shimmer](https://github.com/CommunityToolkit/Labs-Windows/blob/main/components/Shimmer/samples/Shimmer.md) +- [TitleBar](https://github.com/CommunityToolkit/Labs-Windows/blob/main/components/TitleBar/samples/TitleBar.md) +- [TokenView](https://github.com/CommunityToolkit/Labs-Windows/blob/main/components/TokenView/samples/TokenView.md) +- [TransitionHelper](https://github.com/CommunityToolkit/Labs-Windows/blob/main/components/TransitionHelper/samples/TransitionHelper.md) + ## Clone the repository The [tooling](https://github.com/CommunityToolkit/Tooling-Windows-Submodule) is in a submodule, so you'll need to use `--recurse-submodules` when cloning or pulling for the first time: diff --git a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml index 7173b399d..1ead34838 100644 --- a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml +++ b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml @@ -1,4 +1,4 @@ - + - - diff --git a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml.cs b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml.cs index 01e3127dd..413bd1d6e 100644 --- a/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml.cs +++ b/components/MarkdownTextBlock/samples/MarkdownTextBlockCustomSample.xaml.cs @@ -607,5 +607,12 @@ public MarkdownTextBlockCustomSample() _liveConfig = new MarkdownConfig(); _text = _markdown; MarkdownTextBox.Text = "# Hello World\n\n"; + MarkdownTextBlock1.OnLinkClicked += MarkdownTextBlock_OnLinkClicked; + MarkdownTextBlock2.OnLinkClicked += MarkdownTextBlock_OnLinkClicked; + } + + private void MarkdownTextBlock_OnLinkClicked(object? sender, LinkClickedEventArgs e) + { + Debug.WriteLine($"Link Clicked: {e.Uri}"); } } diff --git a/components/MarkdownTextBlock/src/CommunityToolkit.WinUI.Controls.MarkdownTextBlock.csproj b/components/MarkdownTextBlock/src/CommunityToolkit.WinUI.Controls.MarkdownTextBlock.csproj index 6c3c77740..f9a01416e 100644 --- a/components/MarkdownTextBlock/src/CommunityToolkit.WinUI.Controls.MarkdownTextBlock.csproj +++ b/components/MarkdownTextBlock/src/CommunityToolkit.WinUI.Controls.MarkdownTextBlock.csproj @@ -21,9 +21,9 @@ - - - + + + diff --git a/components/MarkdownTextBlock/src/Extensions.cs b/components/MarkdownTextBlock/src/Extensions.cs index 593d8c759..d66339b66 100644 --- a/components/MarkdownTextBlock/src/Extensions.cs +++ b/components/MarkdownTextBlock/src/Extensions.cs @@ -11,6 +11,7 @@ using System.Xml.Linq; using System.Globalization; using Windows.UI.ViewManagement; +using HtmlAgilityPack; namespace CommunityToolkit.Labs.WinUI.MarkdownTextBlock; @@ -722,4 +723,14 @@ public static SolidColorBrush GetAccentColorBrush() return accentBrush; } + + public static string GetAttribute(this HtmlNode node, string attributeName, string defaultValue) + { + if (attributeName == null) + { + throw new ArgumentNullException(nameof(attributeName)); + } + + return node.Attributes?[attributeName]?.Value ?? defaultValue; + } } diff --git a/components/MarkdownTextBlock/src/HtmlWriter.cs b/components/MarkdownTextBlock/src/HtmlWriter.cs index 7875c0f01..3a9ece776 100644 --- a/components/MarkdownTextBlock/src/HtmlWriter.cs +++ b/components/MarkdownTextBlock/src/HtmlWriter.cs @@ -33,11 +33,21 @@ public static void WriteHtml(WinUIRenderer renderer, HtmlNodeCollection nodes) IAddChild hyperLink; if (node.ChildNodes.Any(n => n.Name != "#text")) { - hyperLink = new MyHyperlinkButton(node, renderer.Config.BaseUrl); + var myHyperlinkButton = new MyHyperlinkButton(node, renderer.Config.BaseUrl); + myHyperlinkButton.ClickEvent += (sender, e) => + { + renderer.MarkdownTextBlock.RaiseLinkClickedEvent(((HyperlinkButton)sender).NavigateUri); + }; + hyperLink = myHyperlinkButton; } else { - hyperLink = new MyHyperlink(node, renderer.Config.BaseUrl); + var myHyperlink = new MyHyperlink(node, renderer.Config.BaseUrl); + myHyperlink.ClickEvent += (sender, e) => + { + renderer.MarkdownTextBlock.RaiseLinkClickedEvent(sender.NavigateUri); + }; + hyperLink = myHyperlink; } renderer.Push(hyperLink); WriteHtml(renderer, node.ChildNodes); diff --git a/components/MarkdownTextBlock/src/LinkClickedEventArgs.cs b/components/MarkdownTextBlock/src/LinkClickedEventArgs.cs new file mode 100644 index 000000000..9b1278bc8 --- /dev/null +++ b/components/MarkdownTextBlock/src/LinkClickedEventArgs.cs @@ -0,0 +1,15 @@ +// 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. + +namespace CommunityToolkit.Labs.WinUI.MarkdownTextBlock; + +public class LinkClickedEventArgs : EventArgs +{ + public Uri Uri { get; } + + public LinkClickedEventArgs(Uri uri) + { + this.Uri = uri; + } +} diff --git a/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs b/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs index b3b984797..01e05751f 100644 --- a/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs +++ b/components/MarkdownTextBlock/src/MarkdownTextBlock.xaml.cs @@ -5,6 +5,7 @@ using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.Renderers; using CommunityToolkit.Labs.WinUI.MarkdownTextBlock.TextElements; using Markdig; +using Markdig.Syntax; namespace CommunityToolkit.Labs.WinUI.MarkdownTextBlock; @@ -30,6 +31,12 @@ public partial class MarkdownTextBlock : Control 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); @@ -42,6 +49,16 @@ public string Text set => SetValue(TextProperty, value); } + public MarkdownDocument? MarkdownDocument + { + get => (MarkdownDocument)GetValue(MarkdownDocumentProperty); + private set => SetValue(MarkdownDocumentProperty, value); + } + + public event EventHandler? OnLinkClicked; + + internal void RaiseLinkClickedEvent(Uri uri) => OnLinkClicked?.Invoke(this, new LinkClickedEventArgs(uri)); + private static void OnConfigChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is MarkdownTextBlock self && e.NewValue != null) @@ -54,7 +71,7 @@ private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedE { if (d is MarkdownTextBlock self && e.NewValue != null) { - self.ApplyText(self.Text, true); + self.ApplyText(true); } } @@ -87,16 +104,20 @@ private void ApplyConfig(MarkdownConfig config) } } - private void ApplyText(string text, bool rerender) + private void ApplyText(bool rerender) { - var markdown = Markdown.Parse(text, _pipeline); if (_renderer != null) { if (rerender) { _renderer.ReloadDocument(); } - _renderer.Render(markdown); + + if (!string.IsNullOrEmpty(Text)) + { + this.MarkdownDocument = Markdown.Parse(Text, _pipeline); + _renderer.Render(this.MarkdownDocument); + } } } @@ -106,10 +127,10 @@ private void Build() { if (_renderer == null) { - _renderer = new WinUIRenderer(_document, Config); + _renderer = new WinUIRenderer(_document, Config, this); } _pipeline.Setup(_renderer); - ApplyText(Text, false); + ApplyText(false); } } } diff --git a/components/MarkdownTextBlock/src/MarkdownThemes.cs b/components/MarkdownTextBlock/src/MarkdownThemes.cs index 0b1aaf734..a550f461f 100644 --- a/components/MarkdownTextBlock/src/MarkdownThemes.cs +++ b/components/MarkdownTextBlock/src/MarkdownThemes.cs @@ -49,7 +49,15 @@ public sealed class MarkdownThemes : DependencyObject public FontWeight H6FontWeight { get; set; } = FontWeights.Normal; + public Thickness H1Margin { get; set; } = new(left: 0, top: 14, right: 0, bottom: 0); + public Thickness H2Margin { get; set; } = new(left: 0, top: 14, right: 0, bottom: 0); + public Thickness H3Margin { get; set; } = new(left: 0, top: 14, right: 0, bottom: 0); + public Thickness H4Margin { get; set; } = new(left: 0, top: 14, right: 0, bottom: 0); + public Thickness H5Margin { get; set; } = new(left: 0, top: 8, right: 0, bottom: 0); + public Thickness H6Margin { get; set; } = new(left: 0, top: 8, right: 0, bottom: 0); + public Brush InlineCodeBackground { get; set; } = (Brush)Application.Current.Resources["ExpanderHeaderBackground"]; + public Brush InlineCodeForeground { get; set; } = (Brush)Application.Current.Resources["TextFillColorPrimaryBrush"]; public Brush InlineCodeBorderBrush { get; set; } = new SolidColorBrush(Colors.Gray); diff --git a/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/AutoLinkInlineRenderer.cs b/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/AutoLinkInlineRenderer.cs index 4e9d01f06..5dddedc7e 100644 --- a/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/AutoLinkInlineRenderer.cs +++ b/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/AutoLinkInlineRenderer.cs @@ -26,6 +26,10 @@ protected override void Write(WinUIRenderer renderer, AutolinkInline link) } var autolink = new MyAutolinkInline(link); + autolink.ClickEvent += (sender, e) => + { + renderer.MarkdownTextBlock.RaiseLinkClickedEvent(sender.NavigateUri); + }; renderer.Push(autolink); diff --git a/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/LinkInlineRenderer.cs b/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/LinkInlineRenderer.cs index fa05d400a..5d78c4824 100644 --- a/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/LinkInlineRenderer.cs +++ b/components/MarkdownTextBlock/src/Renderers/ObjectRenderers/Inlines/LinkInlineRenderer.cs @@ -30,11 +30,20 @@ protected override void Write(WinUIRenderer renderer, LinkInline link) { if (link.FirstChild is LinkInline linkInlineChild && linkInlineChild.IsImage) { - renderer.Push(new MyHyperlinkButton(link, renderer.Config.BaseUrl)); + var myHyperlinkButton = new MyHyperlinkButton(link, renderer.Config.BaseUrl); + myHyperlinkButton.ClickEvent += (sender, e) => + { + renderer.MarkdownTextBlock.RaiseLinkClickedEvent(((HyperlinkButton)sender).NavigateUri); + }; + renderer.Push(myHyperlinkButton); } else { var hyperlink = new MyHyperlink(link, renderer.Config.BaseUrl); + hyperlink.ClickEvent += (sender, e) => + { + renderer.MarkdownTextBlock.RaiseLinkClickedEvent(sender.NavigateUri); + }; renderer.Push(hyperlink); } diff --git a/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs b/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs index af4d6cb01..a9f772423 100644 --- a/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs +++ b/components/MarkdownTextBlock/src/Renderers/WinUIRenderer.cs @@ -23,11 +23,13 @@ public MarkdownConfig Config get => _config; set => _config = value; } + public MarkdownTextBlock MarkdownTextBlock { get; } - public WinUIRenderer(MyFlowDocument document, MarkdownConfig config) + public WinUIRenderer(MyFlowDocument document, MarkdownConfig config, MarkdownTextBlock markdownTextBlock) { _buffer = new char[1024]; Config = config; + MarkdownTextBlock = markdownTextBlock; FlowDocument = document; // set style _stack.Push(FlowDocument); diff --git a/components/MarkdownTextBlock/src/TextElements/Html/MyBlock.cs b/components/MarkdownTextBlock/src/TextElements/Html/MyBlock.cs index 4cdc8ba2b..8b3b1ad0d 100644 --- a/components/MarkdownTextBlock/src/TextElements/Html/MyBlock.cs +++ b/components/MarkdownTextBlock/src/TextElements/Html/MyBlock.cs @@ -21,7 +21,7 @@ public TextElement TextElement public MyBlock(HtmlNode block) { _htmlNode = block; - var align = _htmlNode.GetAttributeValue("align", "left"); + var align = _htmlNode.GetAttribute("align", "left"); _richTextBlocks = new List(); _paragraph = new Paragraph(); _paragraph.TextAlignment = align switch diff --git a/components/MarkdownTextBlock/src/TextElements/MyAutolinkInline.cs b/components/MarkdownTextBlock/src/TextElements/MyAutolinkInline.cs index bdea36eae..465d3c54b 100644 --- a/components/MarkdownTextBlock/src/TextElements/MyAutolinkInline.cs +++ b/components/MarkdownTextBlock/src/TextElements/MyAutolinkInline.cs @@ -12,6 +12,18 @@ internal class MyAutolinkInline : IAddChild public TextElement TextElement { get; private set; } + public event TypedEventHandler? ClickEvent + { + add + { + ((Hyperlink)TextElement).Click += value; + } + remove + { + ((Hyperlink)TextElement).Click -= value; + } + } + public MyAutolinkInline(AutolinkInline autoLinkInline) { _autoLinkInline = autoLinkInline; @@ -21,7 +33,6 @@ public MyAutolinkInline(AutolinkInline autoLinkInline) }; } - public void AddChild(IAddChild child) { try diff --git a/components/MarkdownTextBlock/src/TextElements/MyCodeBlock.cs b/components/MarkdownTextBlock/src/TextElements/MyCodeBlock.cs index 862c7de19..f6efcf0c2 100644 --- a/components/MarkdownTextBlock/src/TextElements/MyCodeBlock.cs +++ b/components/MarkdownTextBlock/src/TextElements/MyCodeBlock.cs @@ -30,6 +30,7 @@ public MyCodeBlock(CodeBlock codeBlock, MarkdownConfig config) border.CornerRadius = _config.Themes.CornerRadius; var richTextBlock = new RichTextBlock(); +#if false if (codeBlock is FencedCodeBlock fencedCodeBlock) { //#if !WINAPPSDK @@ -68,17 +69,19 @@ public MyCodeBlock(CodeBlock codeBlock, MarkdownConfig config) } else { - foreach (var line in codeBlock.Lines.Lines) +#endif + + foreach (var line in codeBlock.Lines.Lines) + { + var paragraph = new Paragraph(); + var lineString = line.ToString(); + if (!String.IsNullOrWhiteSpace(lineString)) { - var paragraph = new Paragraph(); - var lineString = line.ToString(); - if (!String.IsNullOrWhiteSpace(lineString)) - { - paragraph.Inlines.Add(new Run() { Text = lineString }); - } - richTextBlock.Blocks.Add(paragraph); + paragraph.Inlines.Add(new Run() { Text = lineString }); } + richTextBlock.Blocks.Add(paragraph); } + border.Child = richTextBlock; container.Child = border; _paragraph.Inlines.Add(container); diff --git a/components/MarkdownTextBlock/src/TextElements/MyHeading.cs b/components/MarkdownTextBlock/src/TextElements/MyHeading.cs index 7e12be877..0c52a1be8 100644 --- a/components/MarkdownTextBlock/src/TextElements/MyHeading.cs +++ b/components/MarkdownTextBlock/src/TextElements/MyHeading.cs @@ -27,26 +27,7 @@ public MyHeading(HeadingBlock headingBlock, MarkdownConfig config) _paragraph = new Paragraph(); _config = config; - var level = headingBlock.Level; - _paragraph.FontSize = level switch - { - 1 => _config.Themes.H1FontSize, - 2 => _config.Themes.H2FontSize, - 3 => _config.Themes.H3FontSize, - 4 => _config.Themes.H4FontSize, - 5 => _config.Themes.H5FontSize, - _ => _config.Themes.H6FontSize, - }; - _paragraph.Foreground = _config.Themes.HeadingForeground; - _paragraph.FontWeight = level switch - { - 1 => _config.Themes.H1FontWeight, - 2 => _config.Themes.H2FontWeight, - 3 => _config.Themes.H3FontWeight, - 4 => _config.Themes.H4FontWeight, - 5 => _config.Themes.H5FontWeight, - _ => _config.Themes.H6FontWeight, - }; + SetHProperties(headingBlock.Level); } public MyHeading(HtmlNode htmlNode, MarkdownConfig config) @@ -55,7 +36,7 @@ public MyHeading(HtmlNode htmlNode, MarkdownConfig config) _paragraph = new Paragraph(); _config = config; - var align = _htmlNode.GetAttributeValue("align", "left"); + var align = _htmlNode.GetAttribute("align", "left"); _paragraph.TextAlignment = align switch { "left" => TextAlignment.Left, @@ -65,7 +46,11 @@ public MyHeading(HtmlNode htmlNode, MarkdownConfig config) _ => TextAlignment.Left, }; - var level = int.Parse(htmlNode.Name.Substring(1)); + SetHProperties(int.Parse(htmlNode.Name.Substring(1))); + } + + private void SetHProperties(int level) + { _paragraph.FontSize = level switch { 1 => _config.Themes.H1FontSize, @@ -85,6 +70,15 @@ public MyHeading(HtmlNode htmlNode, MarkdownConfig config) 5 => _config.Themes.H5FontWeight, _ => _config.Themes.H6FontWeight, }; + _paragraph.Margin = level switch + { + 1 => _config.Themes.H1Margin, + 2 => _config.Themes.H2Margin, + 3 => _config.Themes.H3Margin, + 4 => _config.Themes.H4Margin, + 5 => _config.Themes.H5Margin, + _ => _config.Themes.H6Margin, + }; } public void AddChild(IAddChild child) diff --git a/components/MarkdownTextBlock/src/TextElements/MyHyperlink.cs b/components/MarkdownTextBlock/src/TextElements/MyHyperlink.cs index dba8a0f27..49dfa6338 100644 --- a/components/MarkdownTextBlock/src/TextElements/MyHyperlink.cs +++ b/components/MarkdownTextBlock/src/TextElements/MyHyperlink.cs @@ -14,6 +14,18 @@ internal class MyHyperlink : IAddChild private HtmlNode? _htmlNode; private string? _baseUrl; + public event TypedEventHandler ClickEvent + { + add + { + _hyperlink.Click += value; + } + remove + { + _hyperlink.Click -= value; + } + } + public bool IsHtml => _htmlNode != null; public TextElement TextElement @@ -35,7 +47,7 @@ public MyHyperlink(LinkInline linkInline, string? baseUrl) public MyHyperlink(HtmlNode htmlNode, string? baseUrl) { _baseUrl = baseUrl; - var url = htmlNode.GetAttributeValue("href", "#"); + var url = htmlNode.GetAttribute("href", "#"); _htmlNode = htmlNode; _hyperlink = new Hyperlink() { diff --git a/components/MarkdownTextBlock/src/TextElements/MyHyperlinkButton.cs b/components/MarkdownTextBlock/src/TextElements/MyHyperlinkButton.cs index dbc91ca73..deba711ce 100644 --- a/components/MarkdownTextBlock/src/TextElements/MyHyperlinkButton.cs +++ b/components/MarkdownTextBlock/src/TextElements/MyHyperlinkButton.cs @@ -9,12 +9,24 @@ namespace CommunityToolkit.Labs.WinUI.MarkdownTextBlock.TextElements; internal class MyHyperlinkButton : IAddChild { - private HyperlinkButton? _hyperLinkButton; + private HyperlinkButton _hyperLinkButton; private InlineUIContainer _inlineUIContainer = new InlineUIContainer(); - private MyFlowDocument? _flowDoc; + private MyFlowDocument _flowDoc; private string? _baseUrl; private LinkInline? _linkInline; private HtmlNode? _htmlNode; + + public event RoutedEventHandler? ClickEvent + { + add + { + _hyperLinkButton.Click += value; + } + remove + { + _hyperLinkButton.Click -= value; + } + } public bool IsHtml => _htmlNode != null; @@ -24,43 +36,40 @@ public TextElement TextElement } public MyHyperlinkButton(LinkInline linkInline, string? baseUrl) + : this(linkInline.GetDynamicUrl != null ? linkInline.GetDynamicUrl() ?? linkInline.Url : linkInline.Url, baseUrl, null, linkInline) { - _baseUrl = baseUrl; - var url = linkInline.GetDynamicUrl != null ? linkInline.GetDynamicUrl() ?? linkInline.Url : linkInline.Url; - _linkInline = linkInline; - Init(url, baseUrl); } public MyHyperlinkButton(HtmlNode htmlNode, string? baseUrl) + : this(htmlNode.GetAttribute("href", "#"), baseUrl, htmlNode, null) { - _baseUrl = baseUrl; - _htmlNode = htmlNode; - var url = htmlNode.GetAttributeValue("href", "#"); - Init(url, baseUrl); } - private void Init(string? url, string? baseUrl) + private MyHyperlinkButton(string? url, string? baseUrl, HtmlNode? htmlNode, LinkInline? linkInline) { - _hyperLinkButton = new HyperlinkButton() + _baseUrl = baseUrl; + _htmlNode = htmlNode; + _linkInline = linkInline; + _hyperLinkButton = new HyperlinkButton { NavigateUri = Extensions.GetUri(url, baseUrl), }; _hyperLinkButton.Padding = new Thickness(0); _hyperLinkButton.Margin = new Thickness(0); - if (IsHtml && _htmlNode != null) + if (_htmlNode != null) { _flowDoc = new MyFlowDocument(_htmlNode); } - else if (_linkInline != null) + else { - _flowDoc = new MyFlowDocument(_linkInline); + _flowDoc = new MyFlowDocument(_linkInline!); } _inlineUIContainer.Child = _hyperLinkButton; - _hyperLinkButton.Content = _flowDoc?.RichTextBlock; + _hyperLinkButton.Content = _flowDoc.RichTextBlock; } public void AddChild(IAddChild child) { - _flowDoc?.AddChild(child); + _flowDoc.AddChild(child); } } diff --git a/components/MarkdownTextBlock/src/TextElements/MyImage.cs b/components/MarkdownTextBlock/src/TextElements/MyImage.cs index 56866d007..b03d30e04 100644 --- a/components/MarkdownTextBlock/src/TextElements/MyImage.cs +++ b/components/MarkdownTextBlock/src/TextElements/MyImage.cs @@ -50,20 +50,20 @@ public MyImage(HtmlNode htmlNode, MarkdownConfig? config) #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. { #pragma warning disable CS8601 // Possible null reference assignment. - Uri.TryCreate(htmlNode.GetAttributeValue("src", "#"), UriKind.RelativeOrAbsolute, out _uri); + Uri.TryCreate(htmlNode.GetAttribute("src", "#"), UriKind.RelativeOrAbsolute, out _uri); #pragma warning restore CS8601 // Possible null reference assignment. _htmlNode = htmlNode; _imageProvider = config?.ImageProvider; _svgRenderer = config?.SVGRenderer == null ? new DefaultSVGRenderer() : config.SVGRenderer; Init(); int.TryParse( - htmlNode.GetAttributeValue("width", "0"), + htmlNode.GetAttribute("width", "0"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var width ); int.TryParse( - htmlNode.GetAttributeValue("height", "0"), + htmlNode.GetAttribute("height", "0"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var height diff --git a/components/MarkdownTextBlock/src/TextElements/MyInlineCode.cs b/components/MarkdownTextBlock/src/TextElements/MyInlineCode.cs index 8e97d5963..30c3765d7 100644 --- a/components/MarkdownTextBlock/src/TextElements/MyInlineCode.cs +++ b/components/MarkdownTextBlock/src/TextElements/MyInlineCode.cs @@ -34,6 +34,7 @@ public MyInlineCode(CodeInline codeInline, MarkdownConfig config) border.Transform3D = transform; var textBlock = new TextBlock(); textBlock.FontSize = _config.Themes.InlineCodeFontSize; + textBlock.Foreground = _config.Themes.InlineCodeForeground; textBlock.FontWeight = _config.Themes.InlineCodeFontWeight; textBlock.Text = codeInline.Content.ToString(); border.Child = textBlock; diff --git a/components/MarkdownTextBlock/src/TextElements/MyList.cs b/components/MarkdownTextBlock/src/TextElements/MyList.cs index fc381008b..46b15e1a8 100644 --- a/components/MarkdownTextBlock/src/TextElements/MyList.cs +++ b/components/MarkdownTextBlock/src/TextElements/MyList.cs @@ -45,6 +45,7 @@ public MyList(ListBlock listBlock) } _stackPanel.Orientation = Orientation.Vertical; + _stackPanel.Margin = new Thickness(left: 0, top: 8, right: 0, bottom: 8); _container.Child = _stackPanel; _paragraph.Inlines.Add(_container); } @@ -52,7 +53,8 @@ public MyList(ListBlock listBlock) public void AddChild(IAddChild child) { var grid = new Grid(); - grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) }); + grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(20, GridUnitType.Pixel) }); + grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(10, GridUnitType.Pixel) }); grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }); string bullet; if (_isOrdered) @@ -79,11 +81,12 @@ public void AddChild(IAddChild child) }; textBlock.SetValue(Grid.ColumnProperty, 0); textBlock.VerticalAlignment = VerticalAlignment.Top; + textBlock.TextAlignment = TextAlignment.Right; grid.Children.Add(textBlock); var flowDoc = new MyFlowDocument(); flowDoc.AddChild(child); - flowDoc.RichTextBlock.SetValue(Grid.ColumnProperty, 1); + flowDoc.RichTextBlock.SetValue(Grid.ColumnProperty, 2); flowDoc.RichTextBlock.Padding = new Thickness(0); flowDoc.RichTextBlock.VerticalAlignment = VerticalAlignment.Top; grid.Children.Add(flowDoc.RichTextBlock); diff --git a/components/MarkdownTextBlock/src/TextElements/MyThematicBreak.cs b/components/MarkdownTextBlock/src/TextElements/MyThematicBreak.cs index c1f945ca1..bc06491b9 100644 --- a/components/MarkdownTextBlock/src/TextElements/MyThematicBreak.cs +++ b/components/MarkdownTextBlock/src/TextElements/MyThematicBreak.cs @@ -22,14 +22,14 @@ public MyThematicBreak(ThematicBreakBlock thematicBreakBlock) _paragraph = new Paragraph(); var inlineUIContainer = new InlineUIContainer(); - var border = new Border(); - border.Width = 500; - border.BorderThickness = new Thickness(1); - border.Margin = new Thickness(0, 4, 0, 4); - border.BorderBrush = new SolidColorBrush(Colors.Gray); - border.Height = 1; - border.HorizontalAlignment = HorizontalAlignment.Stretch; - inlineUIContainer.Child = border; + Line line = new Line + { + Stretch = Stretch.Fill, + Stroke = new SolidColorBrush(Colors.Gray), + X2 = 1, + Margin = new Thickness(0, 12, 0, 12) + }; + inlineUIContainer.Child = line; _paragraph.Inlines.Add(inlineUIContainer); } diff --git a/components/MarkdownTextBlock/tests/ExampleMarkdownTextBlockTestClass.cs b/components/MarkdownTextBlock/tests/ExampleMarkdownTextBlockTestClass.cs index 19eef0a75..2c7db300d 100644 --- a/components/MarkdownTextBlock/tests/ExampleMarkdownTextBlockTestClass.cs +++ b/components/MarkdownTextBlock/tests/ExampleMarkdownTextBlockTestClass.cs @@ -131,4 +131,22 @@ public async Task ComplexAsyncLoadUIExampleWithoutDispatcherTest() Assert.IsFalse(component.IsLoaded); } + + [UIThreadTestMethod] + public async Task MarkdownTextBlockEmptyTextValueTest() + { + var component = new MarkdownTextBlock + { + Config = new() + }; + + Assert.IsNotNull(component); + Assert.IsFalse(component.IsLoaded); + + await LoadTestContentAsync(component); + Assert.IsTrue(component.IsLoaded); + + await UnloadTestContentAsync(component); + Assert.IsFalse(component.IsLoaded); + } }