diff --git a/controlgallery/AtomUIGallery/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageProviderPool.g.cs b/controlgallery/AtomUIGallery/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageProviderPool.g.cs index f56acc986..595e447a1 100644 --- a/controlgallery/AtomUIGallery/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageProviderPool.g.cs +++ b/controlgallery/AtomUIGallery/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageProviderPool.g.cs @@ -11792,9 +11792,13 @@ namespace AtomUI.Theme.Language dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.InfoNamespaceLabel] = global::AtomUIGallery.ShowCases.Mentions.en_US.InfoNamespaceLabel; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.InfoPackageLabel] = global::AtomUIGallery.ShowCases.Mentions.en_US.InfoPackageLabel; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextBorderless] = global::AtomUIGallery.ShowCases.Mentions.en_US.P2PlaceholderTextBorderless; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextCustom] = global::AtomUIGallery.ShowCases.Mentions.en_US.P2PlaceholderTextCustom; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextFilled] = global::AtomUIGallery.ShowCases.Mentions.en_US.P2PlaceholderTextFilled; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextInputToMentionPeopleToMentionTag] = global::AtomUIGallery.ShowCases.Mentions.en_US.P2PlaceholderTextInputToMentionPeopleToMentionTag; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextLarge] = global::AtomUIGallery.ShowCases.Mentions.en_US.P2PlaceholderTextLarge; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextMiddle] = global::AtomUIGallery.ShowCases.Mentions.en_US.P2PlaceholderTextMiddle; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextOutlined] = global::AtomUIGallery.ShowCases.Mentions.en_US.P2PlaceholderTextOutlined; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextSmall] = global::AtomUIGallery.ShowCases.Mentions.en_US.P2PlaceholderTextSmall; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextThisIsDisabledMentions] = global::AtomUIGallery.ShowCases.Mentions.en_US.P2PlaceholderTextThisIsDisabledMentions; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextThisIsReadonlyMentions] = global::AtomUIGallery.ShowCases.Mentions.en_US.P2PlaceholderTextThisIsReadonlyMentions; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextUnderlined] = global::AtomUIGallery.ShowCases.Mentions.en_US.P2PlaceholderTextUnderlined; @@ -11805,6 +11809,8 @@ namespace AtomUI.Theme.Language dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.ScenarioApi] = global::AtomUIGallery.ShowCases.Mentions.en_US.ScenarioApi; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.ScenarioDesignToken] = global::AtomUIGallery.ShowCases.Mentions.en_US.ScenarioDesignToken; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.ScenarioExamples] = global::AtomUIGallery.ShowCases.Mentions.en_US.ScenarioExamples; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.SizeTypeDescription] = global::AtomUIGallery.ShowCases.Mentions.en_US.SizeTypeDescription; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.SizeTypeTitle] = global::AtomUIGallery.ShowCases.Mentions.en_US.SizeTypeTitle; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.StatusDescription] = global::AtomUIGallery.ShowCases.Mentions.en_US.StatusDescription; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.StatusTitle] = global::AtomUIGallery.ShowCases.Mentions.en_US.StatusTitle; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.TokenColumnDescription] = global::AtomUIGallery.ShowCases.Mentions.en_US.TokenColumnDescription; @@ -11887,9 +11893,13 @@ namespace AtomUI.Theme.Language dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.InfoNamespaceLabel] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.InfoNamespaceLabel; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.InfoPackageLabel] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.InfoPackageLabel; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextBorderless] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.P2PlaceholderTextBorderless; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextCustom] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.P2PlaceholderTextCustom; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextFilled] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.P2PlaceholderTextFilled; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextInputToMentionPeopleToMentionTag] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.P2PlaceholderTextInputToMentionPeopleToMentionTag; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextLarge] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.P2PlaceholderTextLarge; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextMiddle] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.P2PlaceholderTextMiddle; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextOutlined] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.P2PlaceholderTextOutlined; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextSmall] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.P2PlaceholderTextSmall; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextThisIsDisabledMentions] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.P2PlaceholderTextThisIsDisabledMentions; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextThisIsReadonlyMentions] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.P2PlaceholderTextThisIsReadonlyMentions; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextUnderlined] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.P2PlaceholderTextUnderlined; @@ -11900,6 +11910,8 @@ namespace AtomUI.Theme.Language dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.ScenarioApi] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.ScenarioApi; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.ScenarioDesignToken] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.ScenarioDesignToken; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.ScenarioExamples] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.ScenarioExamples; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.SizeTypeDescription] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.SizeTypeDescription; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.SizeTypeTitle] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.SizeTypeTitle; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.StatusDescription] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.StatusDescription; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.StatusTitle] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.StatusTitle; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.TokenColumnDescription] = global::AtomUIGallery.ShowCases.Mentions.zh_CN.TokenColumnDescription; @@ -11982,9 +11994,13 @@ namespace AtomUI.Theme.Language dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.InfoNamespaceLabel] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.InfoNamespaceLabel; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.InfoPackageLabel] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.InfoPackageLabel; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextBorderless] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.P2PlaceholderTextBorderless; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextCustom] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.P2PlaceholderTextCustom; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextFilled] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.P2PlaceholderTextFilled; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextInputToMentionPeopleToMentionTag] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.P2PlaceholderTextInputToMentionPeopleToMentionTag; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextLarge] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.P2PlaceholderTextLarge; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextMiddle] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.P2PlaceholderTextMiddle; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextOutlined] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.P2PlaceholderTextOutlined; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextSmall] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.P2PlaceholderTextSmall; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextThisIsDisabledMentions] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.P2PlaceholderTextThisIsDisabledMentions; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextThisIsReadonlyMentions] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.P2PlaceholderTextThisIsReadonlyMentions; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.P2PlaceholderTextUnderlined] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.P2PlaceholderTextUnderlined; @@ -11995,6 +12011,8 @@ namespace AtomUI.Theme.Language dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.ScenarioApi] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.ScenarioApi; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.ScenarioDesignToken] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.ScenarioDesignToken; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.ScenarioExamples] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.ScenarioExamples; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.SizeTypeDescription] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.SizeTypeDescription; + dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.SizeTypeTitle] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.SizeTypeTitle; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.StatusDescription] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.StatusDescription; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.StatusTitle] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.StatusTitle; dictionary[global::AtomUIGallery.Localization.MentionsShowCaseLangResourceKind.TokenColumnDescription] = global::AtomUIGallery.ShowCases.Mentions.zh_TW.TokenColumnDescription; diff --git a/controlgallery/AtomUIGallery/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageResourceConst.g.cs b/controlgallery/AtomUIGallery/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageResourceConst.g.cs index 45bb73bf6..b95beefbf 100644 --- a/controlgallery/AtomUIGallery/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageResourceConst.g.cs +++ b/controlgallery/AtomUIGallery/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageResourceConst.g.cs @@ -3770,9 +3770,13 @@ namespace AtomUIGallery.Localization InfoNamespaceLabel, InfoPackageLabel, P2PlaceholderTextBorderless, + P2PlaceholderTextCustom, P2PlaceholderTextFilled, P2PlaceholderTextInputToMentionPeopleToMentionTag, + P2PlaceholderTextLarge, + P2PlaceholderTextMiddle, P2PlaceholderTextOutlined, + P2PlaceholderTextSmall, P2PlaceholderTextThisIsDisabledMentions, P2PlaceholderTextThisIsReadonlyMentions, P2PlaceholderTextUnderlined, @@ -3783,6 +3787,8 @@ namespace AtomUIGallery.Localization ScenarioApi, ScenarioDesignToken, ScenarioExamples, + SizeTypeDescription, + SizeTypeTitle, StatusDescription, StatusTitle, TokenColumnDescription, diff --git a/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/en_US.cs b/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/en_US.cs index cb6e51f74..cbaf47bdc 100644 --- a/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/en_US.cs +++ b/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/en_US.cs @@ -8,6 +8,8 @@ internal partial class en_US : LanguageProvider { public const string BasicTitle = "Basic"; public const string BasicDescription = "The simplest use."; + public const string SizeTypeTitle = "Mentions size"; + public const string SizeTypeDescription = "Mentions supports large, middle, small, and Custom sizes with local height and font overrides."; public const string VariantsTitle = "Variants"; public const string VariantsDescription = "Variants of Mentions, there are four variants: outlined filled borderless and underlined."; public const string AsynchronousLoadingTitle = "Asynchronous loading"; @@ -24,6 +26,10 @@ internal partial class en_US : LanguageProvider public const string AutoSizeDescription = "Height autoSize."; public const string WithClearIconTitle = "With clear icon"; public const string WithClearIconDescription = "Customize clear button."; + public const string P2PlaceholderTextLarge = "Large"; + public const string P2PlaceholderTextMiddle = "Middle"; + public const string P2PlaceholderTextSmall = "Small"; + public const string P2PlaceholderTextCustom = "Custom"; public const string P2PlaceholderTextOutlined = "Outlined"; public const string P2PlaceholderTextFilled = "Filled"; public const string P2PlaceholderTextBorderless = "Borderless"; diff --git a/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/zh_CN.cs b/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/zh_CN.cs index 58bf80f42..4650e48e6 100644 --- a/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/zh_CN.cs +++ b/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/zh_CN.cs @@ -8,6 +8,8 @@ internal partial class zh_CN : LanguageProvider { public const string BasicTitle = "基础用法"; public const string BasicDescription = "最简单的用法。"; + public const string SizeTypeTitle = "Mentions 尺寸"; + public const string SizeTypeDescription = "Mentions 支持大号、中号、小号,也支持通过 Custom 配合本地高度和字号自定义。"; public const string VariantsTitle = "变体"; public const string VariantsDescription = "Mentions 提供四种变体:描边、填充、无边框和下划线。"; public const string AsynchronousLoadingTitle = "异步加载"; @@ -24,6 +26,10 @@ internal partial class zh_CN : LanguageProvider public const string AutoSizeDescription = "高度自动调整。"; public const string WithClearIconTitle = "带清除图标"; public const string WithClearIconDescription = "自定义清除按钮。"; + public const string P2PlaceholderTextLarge = "大号"; + public const string P2PlaceholderTextMiddle = "中号"; + public const string P2PlaceholderTextSmall = "小号"; + public const string P2PlaceholderTextCustom = "自定义"; public const string P2PlaceholderTextOutlined = "线框风格"; public const string P2PlaceholderTextFilled = "填充风格"; public const string P2PlaceholderTextBorderless = "无边框"; diff --git a/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/zh_TW.cs b/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/zh_TW.cs index 410fbfc5c..e10ac3322 100644 --- a/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/zh_TW.cs +++ b/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Localization/zh_TW.cs @@ -8,6 +8,8 @@ internal partial class zh_TW : LanguageProvider { public const string BasicTitle = "基礎用法"; public const string BasicDescription = "最簡單的用法。"; + public const string SizeTypeTitle = "Mentions 尺寸"; + public const string SizeTypeDescription = "Mentions 支持大號、中號、小號,也支持通過 Custom 配合本地高度和字號自定義。"; public const string VariantsTitle = "變體"; public const string VariantsDescription = "Mentions 提供四種變體:描邊、填充、無邊框和下划線。"; public const string AsynchronousLoadingTitle = "異步加載"; @@ -24,6 +26,10 @@ internal partial class zh_TW : LanguageProvider public const string AutoSizeDescription = "高度自動調整。"; public const string WithClearIconTitle = "帶清除圖標"; public const string WithClearIconDescription = "自定義清除按鈕。"; + public const string P2PlaceholderTextLarge = "大號"; + public const string P2PlaceholderTextMiddle = "中號"; + public const string P2PlaceholderTextSmall = "小號"; + public const string P2PlaceholderTextCustom = "自定義"; public const string P2PlaceholderTextOutlined = "線框風格"; public const string P2PlaceholderTextFilled = "填充風格"; public const string P2PlaceholderTextBorderless = "無邊框"; diff --git a/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Views/MentionsShowCase.axaml b/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Views/MentionsShowCase.axaml index f61d29e50..ea12558c1 100644 --- a/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Views/MentionsShowCase.axaml +++ b/controlgallery/AtomUIGallery/ShowCases/DataEntry/Mentions/Views/MentionsShowCase.axaml @@ -2,6 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="AtomUIGallery.ShowCases.Mentions.MentionsShowCase" xmlns:atom="https://atomui.net" + xmlns:antdicons="https://atomui.net/icons/antdesign" xmlns:gallery="https://atomui.net/oss-controls/gallery" xmlns:vm="using:AtomUIGallery.ShowCases.Mentions" x:DataType="vm:MentionsViewModel"> @@ -144,6 +145,41 @@ + + + + + + + + + + + + + ?` | mention 触发前缀。当前触发识别只支持长度为 1 的字符串。默认值为 `["@"]`。 | +| `Split` | `string?` | 插入候选项时使用的分隔符。为空时默认用空格包裹 mention 文本。 | +| `OptionsSource` | `IEnumerable?` | 本地候选项集合。集合变更会同步到内部缓存和候选视图。 | +| `OptionsAsyncLoader` | `IMentionOptionsAsyncLoader?` | 异步候选加载器。存在时,触发候选弹层会优先使用异步加载。 | +| `OptionTemplate` | `IDataTemplate?` | 候选项显示模板。默认模板显示 `IMentionOption.Header`。 | +| `Filter` | `IValueFilter?` | 候选过滤器。为空时使用 contains 过滤。 | +| `FilterValueSelector` | `DefaultFilterValueSelector?` | 从候选项提取过滤文本的 selector。 | +| `DisplayCandidateCount` | `int` | 弹层可显示的候选项数量,用于计算最大高度。默认 `10`。 | + +弹层与异步 API: + +| API | 类型 | 语义 | +| --- | --- | --- | +| `Placement` | `MentionsPlacementMode` | 候选弹层相对触发位置的展开方向,默认 `Bottom`。 | +| `IsDropDownOpen` | `bool` | 候选弹层打开状态。 | +| `ShouldUseOverlayPopup` | `bool` | 是否使用 overlay popup 宿主,默认 `true`。 | +| `AsyncLoadDebounce` | `TimeSpan` | 异步加载前的防抖时间,默认 `TimeSpan.Zero`,值必须非负。 | +| `AsyncLoadTimeout` | `TimeSpan` | 异步加载超时时间,默认 `10` 秒。 | +| `IsLoading` | `bool` | 异步或事件填充过程中的内部 loading 状态,只读公开。 | + +输入表面 API: + +| API | 类型 | 语义 | +| --- | --- | --- | +| `SizeType` | `CustomizableSizeType` | 输入尺寸密度。 | +| `StyleVariant` | `InputControlStyleVariant` | 输入表面样式。 | +| `Status` | `InputControlStatus` | 输入反馈状态。 | +| `ContentLeftAddOn` / `ContentRightAddOn` | `object?` | 内部左右附加内容,传递给内部 `MentionTextArea`。 | +| `ContentLeftAddOnTemplate` / `ContentRightAddOnTemplate` | `IDataTemplate?` | 内部左右附加内容模板。 | +| `IsMotionEnabled` | `bool` | 内部输入壳体、候选列表和 popup 动效开关。 | + +候选项契约: + +| 类型 | 语义 | +| --- | --- | +| `IMentionOption.Key` | 候选项稳定 key,可作为过滤候选值回退。 | +| `IMentionOption.Header` | 候选项显示内容,默认模板显示该值。 | +| `IMentionOption.Value` | 插入文本时优先使用的值。 | +| `IMentionOption.IsEnabled` | 候选项启用状态,供候选列表视觉和选择逻辑使用。 | + +事件契约: + +| 事件 | 语义 | +| --- | --- | +| `CandidateTriggered` | 触发符被识别时触发,事件参数包含触发字符。 | +| `Populating` | 候选弹层准备填充前触发,可取消默认填充并由业务手动更新候选集合。 | +| `Populated` | 候选视图刷新后触发,事件参数包含只读候选视图。 | +| `OptionsLoaded` | 异步 loader 完成后触发,包含加载结果或错误状态。 | +| `DropDownOpening` / `DropDownClosing` | 弹层打开/关闭前触发,可取消。 | +| `DropDownOpened` / `DropDownClosed` | 弹层打开/关闭后触发。 | + +稳定 template part: + +| Template Part | 类型 | 职责 | +| --- | --- | --- | +| `PART_TextArea` | `MentionTextArea` | 文本输入、触发符识别、过滤值同步和候选插入。 | +| `PART_Popup` | `Popup` | 候选弹层宿主。 | +| `PART_CandidateList` | `ICandidateList` / `CandidateList` | 候选项展示、键盘导航、提交和取消。 | +| `PopupFrame` | `Border` | 候选弹层背景、圆角、宽度、高度和 padding。 | +| `LoadingIndicator` | `Spin` | 异步候选加载状态展示。 | + +`EmptyIndicator`、`EmptyIndicatorTemplate`、`IsShowEmptyIndicator` 和 `EmptyIndicatorPadding` 是当前 public surface 的一部分;默认 `MentionsTheme` 尚未把这些属性绑定到候选弹层视觉结构中,维护时不能把它们描述为已经稳定生效的默认视觉契约。 + +## 4. 行为与状态模型 + +Mentions 的核心状态流: + +```text +Value / DefaultValue + ↓ +MentionTextArea.Text + ↓ +Text input + caret position + ↓ +TriggerPrefix scan + ↓ +FilterValue + CandidateOpenRequest + ↓ +Populate / async load / filter + ↓ +CandidateList view + ↓ +Commit option + ↓ +Insert mention text back into Value +``` + +触发符识别从当前 `CaretIndex` 向前扫描,遇到空白或控制字符停止。只有长度为 1 的 `TriggerPrefix` 项会被识别。触发后,`MentionTextArea` 计算触发字符位置和过滤文本,并向外请求打开候选弹层。 + +候选填充优先级: + +```text +OptionsAsyncLoader != null + → async LoadAsync(FilterValue, token) + → OptionsLoaded + → OptionsSource = result.Data + → PopulateComplete() + +OptionsAsyncLoader == null + → Populating(FilterValue) + → if !Cancel PopulateComplete() +``` + +弹层状态优先级: + +```text +Disabled / invisible / window deactivated +> DropDownClosing cancellation +> DropDownOpening cancellation +> IsDropDownOpen +> Candidate trigger state +``` + +键盘行为: + +- 弹层打开时,按键优先交给 `CandidateList.HandleKeyDown()`。 +- `Escape` 取消候选并关闭弹层。 +- `Enter` 在弹层打开时提交当前候选。 +- `F4` 切换弹层打开状态。 +- 弹层关闭时,`Down` 可打开弹层,除非该按键被 XY focus 导航占用。 + +Form 集成以 `Value` 作为表单值。`NotifyValidateStatus` 将 Form 校验状态映射为 `Status=Error/Warning/Default`,Form feedback 控件传递给内部 `MentionTextArea`。 + +## 5. 视觉与主题模型 + +Mentions 的默认视觉由 `MentionsTheme.axaml` 和内部 TextArea 主题协作: + +| 主题或资源 | 职责 | +| --- | --- | +| `MentionsTheme.axaml` | 根模板、`MentionTextArea`、popup、loading、候选列表和 MentionsToken 资源绑定。 | +| `TextAreaTheme.axaml` | 输入表面、placeholder、清除按钮、Form feedback、多行高度和状态视觉。 | +| `CandidateList` 主题 | 候选项容器、选中项、键盘导航和提交取消事件。 | +| `PopupHostToken` | popup 阴影、圆角和 anchor margin。 | +| `MentionsToken` | popup 内容 padding、候选项高度和最小宽度。 | + +输入框本体不由 Mentions 自己重写边框和文本 presenter,而是通过内部 `MentionTextArea` 复用 TextArea 体系。Mentions 的控件级 Token 只服务候选弹层,不承载文本高度、输入边框、状态颜色或 Form feedback。 + +## 6. 控件家族或集成关系 + +Mentions 属于 Data Entry 文本输入控件家族,与 LineEdit/TextArea 共享输入表面、状态、尺寸、清除按钮和 Form 语义。 + +集成关系: + +- `MentionTextArea` 继承 `TextArea`,复用多行输入能力,并增加 trigger scan、过滤值同步和候选插入。 +- `Popup` 提供候选弹层宿主,可通过 `ShouldUseOverlayPopup` 选择 overlay 宿主。 +- `CandidateList` 提供候选项展示、键盘导航、提交和取消。 +- `AsyncSearchLoadCoordinator` 协调异步加载、跳过过期结果、取消和超时。 +- `IFormItemAware` / `IFormItemFeedbackAware` 将 `Value`、校验状态和 feedback 接入 Form。 +- `MentionsToken` 定义候选弹层尺寸相关主题值。 + +## 7. 兼容性不变量 + +维护 Mentions 时必须保持以下不变量: + +- `Value` 必须继续与内部 `MentionTextArea.Text` 双向同步。 +- `DefaultValue` 只在初始化且 `Value` 为空时写入。 +- `TriggerPrefix` 默认值为 `["@"]`,当前触发识别只支持单字符前缀。 +- 触发扫描不能跨越空白或控制字符。 +- `OptionsSource` 集合变化必须同步到内部缓存和候选视图。 +- `OptionsAsyncLoader` 存在时必须优先走异步加载,并通过 `OptionsLoaded` 报告结果。 +- `AsyncLoadDebounce` 变化必须释放旧 timer,避免重复填充。 +- 重新套用模板必须解绑旧 `MentionTextArea`、旧 `Popup` 和旧 `CandidateList` 事件。 +- 弹层打开期间的可见性、启用状态和窗口失活必须关闭弹层。 +- 候选提交必须通过 `MentionTextArea.InsertMentionOption()` 写回文本,保持 undo/redo 快照和 caret/selection 语义。 +- MentionsToken 不承载输入文本、过滤值、候选数据、loading、Form 状态或交互状态。 + +## 8. 专项模型 + +### 8.1 候选过滤模型 + +Mentions 将 `OptionsSource` 缓存为 `List`,再根据 `FilterValue` 构造当前候选视图。默认过滤器是 contains。`FilterValueSelector` 存在时使用 selector 返回值;否则按 `Header`、`Value`、`Key` 的顺序选择过滤文本。 + +过滤过程通过 `_filterInAction` 和 `_cancelRequested` 避免重入时生成过期视图。刷新完成后,候选列表自动选中第一项。 + +### 8.2 异步加载模型 + +`OptionsAsyncLoader` 接收当前过滤值和 cancellation token。`AsyncSearchLoadCoordinator` 负责超时、取消、跳过过期结果和错误状态归一。成功结果会写入 `OptionsSource` 并继续走 `PopulateComplete()`;失败结果只通过 `OptionsLoaded` 通知业务层。 + +### 8.3 候选插入模型 + +提交候选时,控件优先使用 `option.Value`,其次使用 `option.Header`。插入逻辑回溯到当前 mention 触发符位置,选中触发符到当前 caret 的文本片段,然后按 `Split` 或空格规则生成插入文本。 + +`Split` 为单字符时,插入文本以 split 包裹;未设置 split 时,插入文本默认以空格分隔,避免 mention 与相邻普通文本粘连。 + +### 8.4 Popup 定位模型 + +`Placement=Bottom` 映射为 `PlacementMode.BottomEdgeAlignedLeft`,`Placement=Top` 映射为 `PlacementMode.TopEdgeAlignedLeft`。打开候选弹层时,控件根据触发字符 bounds 和 text presenter bounds 计算 popup 偏移,使候选弹层对齐当前触发位置。 + +## 9. 文档导航与验证策略 + +关联文档: + +- [Mentions 桌面版实现原理](implementation.md) +- [Mentions Token 设计](token.md) +- [Mentions Changelog](changelog.md) +- [LineEdit Token 设计](../line-edit/token.md) + +验证策略: + +| 层次 | 验证内容 | +| --- | --- | +| Public API | `Value`、`TriggerPrefix`、候选数据、异步 loader、弹层、输入表面、Form 和事件契约。 | +| 状态 | 触发符识别、过滤值、弹层打开/关闭、loading、disabled、readonly、error、warning、auto-size。 | +| AXAML/Theme | `PART_TextArea`、`PART_Popup`、`PART_CandidateList`、loading、popup shadow、SizeType、StyleVariant。 | +| Token | `PopupContentPadding`、`OptionHeight`、`MinPopupWidth` 的默认值、生成 TokenKind、Gallery Token 表和主题引用。 | +| Gallery | 走查基础、variant、异步加载、自定义触发符、disabled/read-only、placement、status、auto-size 和 clear 示例。 | +| 回归测试 | `MentionsShowCasePageTests`、相关控件测试和 `git diff --check`。 | diff --git a/docs/controls/desktop/data-entry/mentions/token.md b/docs/controls/desktop/data-entry/mentions/token.md new file mode 100644 index 000000000..e24e88a30 --- /dev/null +++ b/docs/controls/desktop/data-entry/mentions/token.md @@ -0,0 +1,89 @@ +# Mentions Token 设计 + +本文档定义 `AtomUI.Desktop.Controls.MentionsToken` 的专属语义、分类、使用范围和兼容边界。控件 Token 的通用分层、命名、计算、Theme Variables 边界和预设色规则见 [AtomUI 控件 Token 设计规范](../../../../engineering/control-token-guidelines.md)。Mentions 整体架构见 [Mentions 桌面版架构设计](overview.md),内部实现原理见 [Mentions 桌面版实现原理](implementation.md),设计和契约变化记录见 [Mentions Changelog](changelog.md)。 + +## 1. 定位 + +MentionsToken 是 Mentions 的组件级 Token scope,只描述候选弹层的结构尺寸。输入框本体由内部 `MentionTextArea` 复用 TextArea / AddOnDecoratedBox / SharedToken 体系;候选列表项的选择、hover、disabled 和文本状态由 CandidateList 主题处理。 + +MentionsToken 不承载以下状态: + +- `Value`、`FilterValue`、`TriggerPrefix`、`OptionsSource`、`OptionsAsyncLoader` 等数据状态。 +- `IsDropDownOpen`、`IsLoading`、`IsReadOnly`、`IsAutoSize`、`Status` 等运行状态。 +- 候选项 selected、hover、disabled、commit、cancel 等交互状态。 +- Popup 当前 offset、placement、实际高度或异步加载结果。 + +## 2. Token 分类 + +### 2.1 候选弹层 padding Token + +- `PopupContentPadding` + +该 Token 控制 `PopupFrame` 内部 padding,并参与 `MaxPopupHeight` 计算。默认值为 `SharedToken.UniformlyPaddingXXS / 2` 的四边等距 padding。 + +### 2.2 候选项高度 Token + +- `OptionHeight` + +该 Token 表示候选项行高基准,默认值为 `SharedToken.ControlHeight`。Mentions 使用它结合 `DisplayCandidateCount` 计算候选弹层最大高度。 + +### 2.3 候选弹层最小宽度 Token + +- `MinPopupWidth` + +该 Token 控制候选弹层最小宽度,默认值为 `120`。实际弹层宽度仍受 popup placement、候选内容和布局约束影响。 + +## 3. 控件专项模型中的 Token 使用 + +MentionsToken 使用路径: + +```text +SharedToken + ↓ +MentionsToken + ↓ +MentionsTheme.axaml + ↓ +PopupFrame + MaxPopupHeight + CandidateList viewport +``` + +主题使用点: + +- `ItemHeight="{atom:MentionsTokenResource OptionHeight}"` +- `PopupContentPadding="{atom:MentionsTokenResource PopupContentPadding}"` +- `MinPopupWidth="{atom:MentionsTokenResource MinPopupWidth}"` + +`MaxPopupHeight` 不是 Token。它由 `ItemHeight`、`DisplayCandidateCount` 和 `PopupContentPadding` 在控件实例上计算,属于运行时布局结果。 + +## 4. 控件家族影响 + +MentionsToken 只影响 Mentions 候选弹层,不直接影响 AutoComplete、Select、TreeSelect、ComboBox 或普通 TextArea。虽然这些控件也有 popup padding、option height 和 min popup width 语义,但它们各自拥有独立 Token scope。 + +调整 MentionsToken 时必须评估: + +- `MentionsTheme.axaml` +- `MentionsShowCase` 的 Design Token 表 +- `MentionsShowCasePageTests` +- 候选弹层 loading、候选列表可视高度和 popup 最小宽度 + +## 5. 兼容性要求 + +MentionsToken 属于 Mentions 主题契约。即使 `MentionsToken` 是 internal 类型,生成的 `MentionsTokenKind`、AXAML resource 使用点和 Gallery Token 表已经形成稳定依赖。 + +Token 变更要求: + +- 不擅自重命名或删除 `PopupContentPadding`、`OptionHeight`、`MinPopupWidth`。 +- 不把实例数据、过滤状态、loading 状态、候选选择状态或 Form 状态迁移为 Token。 +- 不在 MentionsToken 中复制 TextArea 输入边框、字体、清除按钮或校验状态 Token。 +- 不把 `DisplayCandidateCount` 变成 Token;它是实例级行为属性。 +- 需要破坏性变更时,必须先说明影响范围并获得授权。 + +## 6. 验证策略 + +| 改动类型 | 验证要求 | +| --- | --- | +| 修改 `PopupContentPadding` | 验证 popup 内边距、loading 布局、候选项裁剪和 `MaxPopupHeight`。 | +| 修改 `OptionHeight` | 验证候选项高度、键盘选中项可见性和 `DisplayCandidateCount` 对弹层高度的影响。 | +| 修改 `MinPopupWidth` | 验证短候选、长候选、Top/Bottom placement 和 Gallery 示例弹层宽度。 | +| 删除或重命名 Token | 默认不允许;如获授权,需同步 AXAML 引用、生成文件、Gallery Token 表和控件文档。 | +| 文档改动 | 运行 `git diff --check`,检查文档链接存在。 | diff --git a/docs/controls/desktop/data-entry/overview.md b/docs/controls/desktop/data-entry/overview.md index b87be0e64..34408947c 100644 --- a/docs/controls/desktop/data-entry/overview.md +++ b/docs/controls/desktop/data-entry/overview.md @@ -13,6 +13,10 @@ - [SearchEdit 桌面版架构设计](search-edit/overview.md) - [SearchEdit 桌面版实现原理](search-edit/implementation.md) - [SearchEdit Changelog](search-edit/changelog.md) +- [Mentions 桌面版架构设计](mentions/overview.md) +- [Mentions 桌面版实现原理](mentions/implementation.md) +- [Mentions Token 设计](mentions/token.md) +- [Mentions Changelog](mentions/changelog.md) - [NumericUpDown 桌面版架构设计](numeric-up-down/overview.md) - [NumericUpDown 桌面版实现原理](numeric-up-down/implementation.md) - [NumericUpDown Token 设计](numeric-up-down/token.md) diff --git a/src/AtomUI.Desktop.Controls/Input/Themes/TextAreaDecoratedBoxTheme.axaml b/src/AtomUI.Desktop.Controls/Input/Themes/TextAreaDecoratedBoxTheme.axaml index bf38dc34e..1a2eb0e46 100644 --- a/src/AtomUI.Desktop.Controls/Input/Themes/TextAreaDecoratedBoxTheme.axaml +++ b/src/AtomUI.Desktop.Controls/Input/Themes/TextAreaDecoratedBoxTheme.axaml @@ -67,6 +67,9 @@ +