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 @@ -70,8 +70,8 @@ field. The caret, selection, undo, IME composition and clipboard shortcuts are t
copy under the frame. The error row swaps its whole message at once.
6. **Meter row**: 12 px below the field or its error row. Four equal segments, 4 px tall, with 5 px gaps, on a track in
the border color.
7. **Strength word**: a 72 px slot at the end of the meter row, 12 px from the meter, right aligned, in the medium
weight of the small body size. It is empty while the field is empty.
7. **Strength word**: At the end of the meter row, a slot at least 72 px wide that grows for localized labels,
12 px from the meter, right aligned, in the medium weight of the small body size. It is empty while the field is empty.
8. **Requirement list** (`Rules`): 16 px below the meter, 6 px between rules. Each row has a 16 px circle that gains a
faint success tint and a tick when the rule is met, then the rule label. An unmet rule with a `Remaining` function
also shows a rolling count such as "4 more" in the muted color.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: 密码强度
summary: 在输入新密码时显示其强度。
source-hash: 03a81b19e445
source-hash: 1b9e076740df
---

<Demo name="Create" />
Expand Down Expand Up @@ -48,7 +48,7 @@ source-hash: 03a81b19e445
4. **显示切换按钮**:位于外框末端的 34 px 方形按钮,圆角 13 px,内含 18 px 的眼睛图标。按下时缩放至 94%;显示密码时,它会报告其开启状态。
5. **说明行与错误行**(`Description`、`ErrorMessage`):与 `Input` 共用的辅助行和错误行,位于外框下方,12 px 文案。错误行会整体替换其消息。
6. **强度计行**:位于字段或其错误行下方 12 px。四段等宽的 4 px 高色段,间隔 5 px,底色为边框颜色。
7. **强度文字**:强度计行末端的 72 px 区域,与强度计相距 12 px,右对齐,使用小号正文的中等字重。字段为空时它也为空。
7. **强度文字**:强度计行末端至少 72 px 的区域,随本地化文字增宽,与强度计相距 12 px,右对齐,使用小号正文的中等字重。字段为空时它也为空。
8. **规则列表**(`Rules`):位于强度计下方 16 px,规则之间间隔 6 px。每行有一个 16 px 的圆圈,规则满足时圆圈带淡淡的成功色并显示对勾,之后是规则文字。未满足且带有 `Remaining` 函数的规则,还会以弱化颜色显示滚动计数,例如“还差 4 个”。

### 强度等级
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: 密碼強度
summary: 在輸入新密碼時顯示其強度。
source-hash: 03a81b19e445
source-hash: 1b9e076740df
---

<Demo name="Create" />
Expand Down Expand Up @@ -48,7 +48,7 @@ source-hash: 03a81b19e445
4. **顯示切換按鈕**:位於外框末端的 34 px 方形按鈕,圓角 13 px,內含 18 px 的眼睛圖示。按下時縮放至 94%;顯示密碼時,它會回報其開啟狀態。
5. **說明列與錯誤列**(`Description`、`ErrorMessage`):與 `Input` 共用的輔助列和錯誤列,位於外框下方,12 px 文案。錯誤列會整則替換其訊息。
6. **強度計列**:位於欄位或其錯誤列下方 12 px。四段等寬的 4 px 高色段,間隔 5 px,底色為邊框顏色。
7. **強度文字**:強度計列末端的 72 px 區域,與強度計相距 12 px,靠右對齊,使用小號內文的中等字重。欄位為空時它也會是空的。
7. **強度文字**:強度計列末端至少 72 px 的區域,隨本地化文字增寬,與強度計相距 12 px,靠右對齊,使用小號內文的中等字重。欄位為空時它也會是空的。
8. **規則清單**(`Rules`):位於強度計下方 16 px,規則之間間隔 6 px。每列有一個 16 px 的圓圈,規則符合時圓圈帶淡淡的成功色並顯示勾號,之後是規則文字。未符合且帶有 `Remaining` 函式的規則,還會以淡化顏色顯示滾動計數,例如「還差 4 個」。

### 強度等級
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal sealed class PasswordStrengthToken : AbstractControlDesignToken
public double SegmentHeight { get; set; }
public double SegmentGap { get; set; }

/// <summary>The strength word's fixed slot: 4.5rem, 12px from the meter, 1.4em tall.</summary>
/// <summary>The strength word's minimum slot: 4.5rem, growing for localized labels, 12px from the meter, 1.4em tall.</summary>
public double WordWidth { get; set; }
public Thickness WordMargin { get; set; }
public double WordLineHeight { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
StrongTone="{arc:ArcDesignTokenResource Success}" />
<arc:FieldSwapText Name="PART_Word"
Grid.Column="1"
Width="{arc:PasswordStrengthTokenResource WordWidth}"
MinWidth="{arc:PasswordStrengthTokenResource WordWidth}"
Margin="{arc:PasswordStrengthTokenResource WordMargin}"
TextAlignment="Right"
ClipToBounds="False"
Expand Down
47 changes: 47 additions & 0 deletions tests/TKCode.Arc.Tests/TextFields/PasswordStrengthTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,58 @@
using Avalonia;
using Avalonia.Headless.XUnit;
using Avalonia.Media;
using Avalonia.Threading;
using Avalonia.VisualTree;
using TKCode.Arc.Motion;

namespace TKCode.Arc.Tests.TextFields;

public class PasswordStrengthTests
{
[AvaloniaTheory]
[InlineData(280, ArcMotionLevel.Off)]
[InlineData(480, ArcMotionLevel.Off)]
[InlineData(280, ArcMotionLevel.Full)]
[InlineData(480, ArcMotionLevel.Full)]
public void Localized_Strength_Labels_Keep_Their_Gap_And_Fit_The_Field(int width, ArcMotionLevel level)
{
var clock = new ManualFrameClock();
using var installed = clock.Install();
var field = new PasswordStrength { Label = "Password", Width = width };
var window = TestHelpers.Show(field, level);
try
{
foreach (var label in new[] { "Strong", "符合输入要求", "Conforme", "Good" })
{
field.Messages = new PasswordStrengthMessages { Strong = label };
field.Text = "Correct-Horse-9";
Dispatcher.UIThread.RunJobs();
clock.Advance(TimeSpan.FromSeconds(1));
Dispatcher.UIThread.RunJobs();
var word = field.GetVisualDescendants().OfType<FieldSwapText>().Single();
var meter = field.GetVisualDescendants().OfType<PasswordStrengthMeter>().Single();
var drawing = new DrawingGroup();
using (var context = drawing.Open())
{
word.Render(context);
}
var bounds = drawing.GetBounds();
var textOrigin = word.TranslatePoint(default, window)!.Value;
var meterOrigin = meter.TranslatePoint(default, window)!.Value;
var fieldOrigin = field.TranslatePoint(default, window)!.Value;
(textOrigin.X + bounds.Left - meterOrigin.X - meter.Bounds.Width)
.ShouldBeGreaterThanOrEqualTo(11.5, label);
(textOrigin.X + bounds.Right).ShouldBeLessThanOrEqualTo(fieldOrigin.X + width + 0.5);
word.Bounds.Width.ShouldBeGreaterThanOrEqualTo(72);
meter.Bounds.Width.ShouldBeGreaterThan(0);
}
}
finally
{
window.Close();
}
}

[Theory]
[InlineData("", 0, false)]
[InlineData("Abc1!", 1, true)]
Expand Down
Loading