/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { KeyCode } from '@ohos.multimodalInput.keyCode';
import measure from '@ohos.measure';
import mediaquery from '@ohos.mediaquery';
import resourceManager from '@ohos.resourceManager';
import { ColorMetrics, LengthMetrics, LengthUnit } from '@ohos.arkui.node';
import EnvironmentCallback from '@ohos.app.ability.EnvironmentCallback';
import { SymbolGlyphModifier } from '@ohos.arkui.modifier';
import componentUtils from '@ohos.arkui.componentUtils';
import hilog from '@ohos.hilog';
import common from '@ohos.app.ability.common';
const RESOURCE_TYPE_STRING = 10003;
const RESOURCE_TYPE_FLOAT = 10002;
const RESOURCE_TYPE_INTEGER = 10007;
export enum ChipSize {
NORMAL = "NORMAL",
SMALL = "SMALL"
}
enum IconType {
PREFIX_ICON = 'PREFIXICON',
SUFFIX_ICON = 'SUFFIXICON',
PREFIX_SYMBOL = 'PREFIXSYMBOL',
SUFFIX_SYMBOL = 'SUFFIXSYMBOL',
}
enum BreakPointsType {
SM = "SM",
MD = "MD",
LG = "LG"
}
export enum AccessibilitySelectedType {
CLICKED = 0,
CHECKED = 1,
SELECTED = 2,
}
export interface IconCommonOptions {
src: ResourceStr;
size?: SizeOptions;
fillColor?: ResourceColor;
activatedFillColor?: ResourceColor;
}
export interface SuffixIconOptions extends IconCommonOptions {
action?: () => void;
accessibilityText?: ResourceStr;
accessibilityDescription?: ResourceStr;
accessibilityLevel?: string;
}
export interface PrefixIconOptions extends IconCommonOptions {}
export interface AccessibilityOptions {
accessibilityLevel?: string;
accessibilityText?: ResourceStr;
accessibilityDescription?: ResourceStr;
}
export interface CloseOptions extends AccessibilityOptions {}
export interface ChipSymbolGlyphOptions {
normal?: SymbolGlyphModifier;
activated?: SymbolGlyphModifier;
}
export interface ChipSuffixSymbolGlyphOptions {
normalAccessibility?: AccessibilityOptions;
activatedAccessibility?: AccessibilityOptions;
action?: VoidCallback;
}
export interface LabelMarginOptions {
left?: Dimension;
right?: Dimension;
}
export interface LocalizedLabelMarginOptions {
start?: LengthMetrics;
end?: LengthMetrics;
}
export interface LabelOptions {
text: string;
fontSize?: Dimension;
fontColor?: ResourceColor;
activatedFontColor?: ResourceColor;
fontFamily?: string;
labelMargin?: LabelMarginOptions;
localizedLabelMargin?: LocalizedLabelMarginOptions;
}
interface IconTheme {
normalSize: SizeOptions;
smallSize: SizeOptions;
fillColor: ResourceColor;
activatedFillColor: ResourceColor;
focusFillColor: ResourceColor;
focusActivatedColor: ResourceColor;
}
interface PrefixIconTheme extends IconTheme {}
interface SuffixIconTheme extends IconTheme {
defaultDeleteIcon: ResourceStr;
focusable: boolean;
isShowMargin: Resource;
}
interface DefaultSymbolTheme {
normalFontColor: Array<ResourceColor>;
activatedFontColor: Array<ResourceColor>;
smallSymbolFontSize: Length;
normalSymbolFontSize: Length;
defaultEffect: number;
}
interface LabelTheme {
normalFontSize: Dimension;
smallFontSize: Dimension;
focusFontColor: ResourceColor;
focusActiveFontColor: ResourceColor;
fontColor: ResourceColor;
activatedFontColor: ResourceColor;
fontFamily: string;
fontWeight: Resource;
normalMargin: Margin;
localizedNormalMargin: LocalizedMargin;
smallMargin: Margin;
localizedSmallMargin: LocalizedMargin;
defaultFontSize: Dimension;
}
interface ChipNodeOpacity {
normal: number;
hover: number;
pressed: number;
}
interface ChipNodeConstraintWidth {
breakPointMinWidth: number,
breakPointSmMaxWidth: number,
breakPointMdMaxWidth: number,
breakPointLgMaxWidth: number,
}
interface ChipNodeTheme {
suitAgeScale: number;
minLabelWidth: Dimension;
normalHeight: Dimension;
smallHeight: Dimension;
enabled: boolean;
activated: boolean;
backgroundColor: ResourceColor;
activatedBackgroundColor: ResourceColor;
focusOutlineColor: ResourceColor;
borderColor: ResourceColor,
defaultBorderWidth: Resource;
activatedBorderColor: ResourceColor;
focusBtnScaleX: Resource;
focusBtnScaleY: Resource;
focusBgColor: ResourceColor;
focusActivatedBgColor: ResourceColor;
normalShadowStyle: Resource;
smallShadowStyle: Resource;
focusOutlineMargin: number;
normalBorderRadius: Dimension;
smallBorderRadius: Dimension;
borderWidth: number;
localizedNormalPadding: LocalizedPadding;
localizedSmallPadding: LocalizedPadding;
hoverBlendColor: ResourceColor;
pressedBlendColor: ResourceColor;
opacity: ChipNodeOpacity;
breakPointConstraintWidth: ChipNodeConstraintWidth;
}
interface ChipTheme {
prefixIcon: PrefixIconTheme;
label: LabelTheme;
suffixIcon: SuffixIconTheme;
defaultSymbol: DefaultSymbolTheme;
chipNode: ChipNodeTheme;
}
const noop = () => {
};
interface ChipOptions {
prefixIcon?: PrefixIconOptions;
prefixSymbol?: ChipSymbolGlyphOptions;
label: LabelOptions;
suffixIcon?: SuffixIconOptions;
suffixSymbol?: ChipSymbolGlyphOptions;
suffixSymbolOptions?: ChipSuffixSymbolGlyphOptions;
allowClose?: boolean;
closeOptions?: CloseOptions;
enabled?: boolean;
activated?: boolean;
backgroundColor?: ResourceColor;
activatedBackgroundColor?: ResourceColor;
borderRadius?: Dimension;
size?: ChipSize | SizeOptions;
direction?: Direction;
accessibilitySelectedType?: AccessibilitySelectedType;
accessibilityDescription?: ResourceStr;
accessibilityLevel?: string;
onClose?: () => void
onClicked?: () => void
}
@Builder
export function Chip(options: ChipOptions) {
ChipComponent({
chipSize: options.size,
prefixIcon: options.prefixIcon,
prefixSymbol: options.prefixSymbol,
label: options.label,
suffixIcon: options.suffixIcon,
suffixSymbol: options.suffixSymbol,
suffixSymbolOptions: options.suffixSymbolOptions,
allowClose: options.allowClose,
closeOptions: options.closeOptions,
chipEnabled: options.enabled,
chipActivated: options.activated,
chipNodeBackgroundColor: options.backgroundColor,
chipNodeActivatedBackgroundColor: options.activatedBackgroundColor,
chipNodeRadius: options.borderRadius,
chipDirection: options.direction,
chipAccessibilitySelectedType: options.accessibilitySelectedType,
chipAccessibilityDescription: options.accessibilityDescription,
chipAccessibilityLevel: options.accessibilityLevel,
onClose: options.onClose,
onClicked: options.onClicked,
})
}
function isValidString(dimension: string, regex: RegExp): boolean {
const matches = dimension.match(regex);
if (!matches || matches.length < 3) {
return false;
}
const value = Number.parseFloat(matches[1]);
return value >= 0;
}
function isValidDimensionString(dimension: string): boolean {
return isValidString(dimension, new RegExp('(-?\\d+(?:\\.\\d+)?)_?(fp|vp|px|lpx|%)?$', 'i'));
}
function isValidResource(context: Context | undefined, value: Resource) {
const resourceManager = context?.resourceManager;
if (value === void (0) || value === null || resourceManager === void (0)) {
return false;
}
if (value.type !== RESOURCE_TYPE_STRING && value.type !== RESOURCE_TYPE_INTEGER &&
value.type !== RESOURCE_TYPE_FLOAT) {
return false;
}
if (value.type === RESOURCE_TYPE_INTEGER || value.type === RESOURCE_TYPE_FLOAT) {
if (resourceManager.getNumber(value.id) >= 0) {
return true;
} else {
return false;
}
}
if (value.type === RESOURCE_TYPE_STRING && !isValidDimensionString(resourceManager.getStringSync(value.id))) {
return false;
} else {
return true;
}
}
@Component
export struct ChipComponent {
private theme: ChipTheme = {
prefixIcon: {
normalSize: {
width: $r('sys.float.chip_normal_icon_size'),
height: $r('sys.float.chip_normal_icon_size')
},
smallSize: {
width: $r('sys.float.chip_small_icon_size'),
height: $r('sys.float.chip_small_icon_size')
},
fillColor: $r('sys.color.chip_usually_icon_color'),
activatedFillColor: $r('sys.color.chip_active_icon_color'),
focusFillColor: $r('sys.color.chip_icon_focus_fill'),
focusActivatedColor: $r('sys.color.chip_icon_activated_focus_color'),
},
label: {
normalFontSize: $r('sys.float.chip_normal_font_size'),
smallFontSize: $r('sys.float.chip_small_font_size'),
focusFontColor: $r('sys.color.chip_focus_text'),
focusActiveFontColor: $r('sys.color.chip_activated_focus_font_color'),
fontColor: $r('sys.color.chip_font_color'),
activatedFontColor: $r('sys.color.chip_activated_fontcolor'),
fontFamily: "HarmonyOS Sans",
fontWeight: $r('sys.float.chip_text_font_weight'),
normalMargin: {
left: 6,
right: 6,
top: 0,
bottom: 0
},
smallMargin: {
left: 4,
right: 4,
top: 0,
bottom: 0
},
defaultFontSize: 14,
localizedNormalMargin: {
start: LengthMetrics.resource($r('sys.float.chip_normal_text_margin')),
end: LengthMetrics.resource($r('sys.float.chip_normal_text_margin')),
top: LengthMetrics.vp(0),
bottom: LengthMetrics.vp(0)
},
localizedSmallMargin: {
start: LengthMetrics.resource($r('sys.float.chip_small_text_margin')),
end: LengthMetrics.resource($r('sys.float.chip_small_text_margin')),
top: LengthMetrics.vp(0),
bottom: LengthMetrics.vp(0),
}
},
suffixIcon: {
normalSize: {
width: $r('sys.float.chip_normal_icon_size'),
height: $r('sys.float.chip_normal_icon_size')
},
smallSize: {
width: $r('sys.float.chip_small_icon_size'),
height: $r('sys.float.chip_small_icon_size')
},
fillColor: $r('sys.color.chip_usually_icon_color'),
activatedFillColor: $r('sys.color.chip_active_icon_color'),
focusFillColor: $r('sys.color.chip_icon_focus_fill'),
focusActivatedColor: $r('sys.color.chip_icon_activated_focus_color'),
defaultDeleteIcon: $r('sys.media.ohos_ic_public_cancel', 16, 16),
focusable: false,
isShowMargin: $r('sys.float.chip_show_close_icon_margin'),
},
defaultSymbol: {
normalFontColor: [$r('sys.color.ohos_id_color_secondary')],
activatedFontColor: [$r('sys.color.ohos_id_color_text_primary_contrary')],
smallSymbolFontSize: LengthMetrics.resource($r('sys.float.chip_small_icon_size')).value as Length,
normalSymbolFontSize: LengthMetrics.resource($r('sys.float.chip_normal_icon_size')).value as Length,
defaultEffect: -1,
},
chipNode: {
suitAgeScale: 1.75,
minLabelWidth: 12,
normalHeight: $r('sys.float.chip_normal_height'),
smallHeight: $r('sys.float.chip_small_height'),
enabled: true,
activated: false,
backgroundColor: $r('sys.color.chip_background_color'),
activatedBackgroundColor: $r('sys.color.chip_container_activated_color'),
focusOutlineColor: $r('sys.color.ohos_id_color_focused_outline'),
focusOutlineMargin: 2,
borderColor: $r('sys.color.chip_border_color'),
defaultBorderWidth: $r('sys.float.chip_border_width'),
activatedBorderColor: $r('sys.color.chip_activated_border_color'),
normalBorderRadius: $r('sys.float.chip_border_radius_normal'),
smallBorderRadius: $r('sys.float.chip_border_radius_small'),
borderWidth: 2,
focusBtnScaleX: $r('sys.float.chip_focused_btn_scale'),
focusBtnScaleY: $r('sys.float.chip_focused_btn_scale'),
localizedNormalPadding: {
start: LengthMetrics.resource($r('sys.float.chip_normal_text_padding')),
end: LengthMetrics.resource($r('sys.float.chip_normal_text_padding')),
top: LengthMetrics.vp(4),
bottom: LengthMetrics.vp(4)
},
localizedSmallPadding: {
start: LengthMetrics.resource($r('sys.float.chip_small_text_padding')),
end: LengthMetrics.resource($r('sys.float.chip_small_text_padding')),
top: LengthMetrics.vp(4),
bottom: LengthMetrics.vp(4)
},
hoverBlendColor: $r('sys.color.chip_hover_color'),
pressedBlendColor: $r('sys.color.chip_press_color'),
focusBgColor: $r('sys.color.chip_focus_color'),
focusActivatedBgColor: $r('sys.color.chip_container_activated_focus_color'),
opacity: { normal: 1, hover: 0.95, pressed: 0.9 },
normalShadowStyle: $r('sys.float.chip_normal_shadow_style'),
smallShadowStyle: $r('sys.float.chip_small_shadow_style'),
breakPointConstraintWidth: {
breakPointMinWidth: 128,
breakPointSmMaxWidth: 156,
breakPointMdMaxWidth: 280,
breakPointLgMaxWidth: 400
}
}
};
@Prop chipSize: ChipSize | SizeOptions = ChipSize.NORMAL
@Prop allowClose: boolean = true
@Prop closeOptions?: CloseOptions
@Prop chipDirection: Direction = Direction.Auto
@Prop prefixIcon: PrefixIconOptions = { src: "" }
@Prop prefixSymbol: ChipSymbolGlyphOptions
@Prop label: LabelOptions = { text: "" }
@Prop suffixIcon: SuffixIconOptions = { src: "" }
@Prop suffixSymbol?: ChipSymbolGlyphOptions
@Prop suffixSymbolOptions?: ChipSuffixSymbolGlyphOptions
@Prop chipNodeBackgroundColor: ResourceColor = this.theme.chipNode.backgroundColor
@Prop chipNodeActivatedBackgroundColor: ResourceColor = this.theme.chipNode.activatedBackgroundColor
@State isHovering: boolean = false;
@Prop chipNodeRadius: Dimension | undefined = void (0)
@Prop chipEnabled: boolean = true
@Prop chipActivated?: boolean
@Prop chipAccessibilitySelectedType?: AccessibilitySelectedType
@Prop chipAccessibilityDescription?: ResourceStr
@Prop chipAccessibilityLevel?: string
@State isHover: boolean = false
@State chipScale: ScaleOptions = { x: 1, y: 1 }
@State chipOpacity: number = 1
@State chipBlendColor: ResourceColor = Color.Transparent
@State deleteChip: boolean = false
@State chipNodeOnFocus: boolean = false
@State useDefaultSuffixIcon: boolean = false
private chipNodeSize: SizeOptions = {}
private onClose: () => void = noop
private onClicked: () => void = noop
@State suffixIconOnFocus: boolean = false
@State chipBreakPoints: BreakPointsType = BreakPointsType.SM
private smListener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(0vp<width) and (width<600vp)')
private mdListener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(600vp<=width) and (width<840vp)')
private lgListener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(840vp<=width)')
private isSuffixIconFocusStyleCustomized: boolean =
this.resourceToNumber(this.theme.suffixIcon.isShowMargin, 0) !== 0;
@State private isShowPressedBackGroundColor: boolean = false
@State fontSizeScale: number | undefined = 0
@State fontWeightScale: number | undefined = 0
private callbacks: EnvironmentCallback = {
onConfigurationUpdated: (configuration) => {
this.fontSizeScale = configuration.fontSizeScale;
this.fontWeightScale = configuration.fontWeightScale;
}, onMemoryLevel() {
}
}
private callbackId: number | undefined = undefined
@State prefixSymbolWidth: Length | undefined =
this.toVp(componentUtils.getRectangleById('PrefixSymbolGlyph')?.size?.width);
@State suffixSymbolWidth: Length | undefined =
this.toVp(componentUtils.getRectangleById('SuffixSymbolGlyph')?.size?.width);
@State allowCloseSymbolWidth: Length | undefined =
this.toVp(componentUtils.getRectangleById('AllowCloseSymbolGlyph')?.size?.width);
@State symbolEffect: SymbolEffect = new SymbolEffect();
private isChipSizeEnum(): boolean {
return typeof (this.chipSize) === 'string'
}
private isShowCloseIconMargin(): boolean {
return this.resourceToNumber(this.theme.suffixIcon.isShowMargin, 0) !== 0 && this.allowClose;
}
private getLabelFontSize(): Dimension {
if (this.label?.fontSize !== void (0) && this.toVp(this.label.fontSize) >= 0) {
return this.label.fontSize
} else {
if (this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL) {
try {
resourceManager.getSystemResourceManager()
.getNumberByName((((this.theme.label.smallFontSize as Resource).params as string[])[0]).split('.')[2])
return this.theme.label.smallFontSize
} catch (error) {
return this.theme.label.defaultFontSize
}
} else {
try {
resourceManager.getSystemResourceManager()
.getNumberByName((((this.theme.label.normalFontSize as Resource).params as string[])[0]).split('.')[2])
return this.theme.label.normalFontSize
} catch (error) {
return this.theme.label.defaultFontSize
}
}
}
}
private defaultSymbolFontsize(): Length {
return this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL ? this.theme.defaultSymbol.smallSymbolFontSize :
this.theme.defaultSymbol.normalSymbolFontSize;
}
private resourceToVp(resource: Resource): number {
let metrics = LengthMetrics.resource(resource);
return this.lengthMetricsToVp(metrics);
}
private getActiveFontColor(): ResourceColor {
return this.chipNodeOnFocus ? this.theme.label.focusActiveFontColor : this.theme.label.activatedFontColor;
}
private getFontColor(): ResourceColor {
return this.chipNodeOnFocus ? this.theme.label.focusFontColor : this.theme.label.fontColor;
}
private getLabelFontColor(): ResourceColor {
if (this.getChipActive()) {
return this.label?.activatedFontColor ?? this.getActiveFontColor();
}
return this.label?.fontColor ?? this.getFontColor();
}
private getLabelFontFamily(): string {
return this.label?.fontFamily ?? this.theme.label.fontFamily
}
private getLabelFontWeight(): FontWeight {
if (this.getChipActive()) {
return FontWeight.Medium;
}
return this.resourceToNumber(this.theme.label.fontWeight, FontWeight.Regular) as FontWeight;
}
private lengthMetricsToVp(lengthMetrics?: LengthMetrics): number {
let defaultValue: number = 0;
if (lengthMetrics) {
switch (lengthMetrics.unit) {
case LengthUnit.PX:
return px2vp(lengthMetrics.value)
case LengthUnit.VP:
return lengthMetrics.value
case LengthUnit.FP:
return px2vp(fp2px(lengthMetrics.value))
case LengthUnit.PERCENT:
return Number.NEGATIVE_INFINITY
case LengthUnit.LPX:
return px2vp(lpx2px(lengthMetrics.value))
}
}
return defaultValue;
}
private toVp(value: Dimension | Length | undefined): number {
if (value === void (0)) {
return Number.NEGATIVE_INFINITY
}
switch (typeof (value)) {
case 'number':
return value as number
case 'object':
try {
let returnValue = this.lengthMetricsToVp(LengthMetrics.resource(value));
if (returnValue === 0 &&
!isValidResource(getContext(this), value)) {
return Number.NEGATIVE_INFINITY;
}
return returnValue;
} catch (error) {
return Number.NEGATIVE_INFINITY
}
case 'string':
let regex: RegExp = new RegExp("(-?\\d+(?:\\.\\d+)?)_?(fp|vp|px|lpx|%)?$", "i");
let matches: RegExpMatchArray | null = value.match(regex);
if (!matches) {
return Number.NEGATIVE_INFINITY
}
let length: number = Number(matches?.[1] ?? 0);
let unit: string = matches?.[2] ?? 'vp'
switch (unit.toLowerCase()) {
case 'px':
length = px2vp(length)
break
case 'fp':
length = px2vp(fp2px(length))
break
case 'lpx':
length = px2vp(lpx2px(length))
break
case '%':
length = Number.NEGATIVE_INFINITY
break
case 'vp':
break
default:
break
}
return length
default:
return Number.NEGATIVE_INFINITY
}
}
private getChipNodeBorderWidth(): number {
return this.resourceToVp(this.theme.chipNode.defaultBorderWidth);
}
private getChipNodeBorderColor(): ResourceColor {
let themeChipNode = this.theme.chipNode;
return this.getChipActive() ? themeChipNode.activatedBorderColor : themeChipNode.borderColor;
}
private getLabelMargin(): Margin {
let labelMargin: Margin = { left: 0, right: 0 }
if (this.label?.labelMargin?.left !== void (0) && this.toVp(this.label.labelMargin.left) >= 0) {
labelMargin.left = this.label?.labelMargin?.left
} else if ((this.prefixSymbol?.normal || this.prefixSymbol?.activated) || this.prefixIcon?.src) {
if (this.isChipSizeEnum() && this.chipSize == ChipSize.SMALL) {
labelMargin.left = this.theme.label.smallMargin.left
} else {
labelMargin.left = this.theme.label.normalMargin.left
}
}
if (this.label?.labelMargin?.right !== void (0) && this.toVp(this.label.labelMargin.right) >= 0) {
labelMargin.right = this.label?.labelMargin?.right
} else if ((this.suffixSymbol?.normal || this.suffixSymbol?.activated) ||
this.suffixIcon?.src || this.useDefaultSuffixIcon) {
if (this.isChipSizeEnum() && this.chipSize == ChipSize.SMALL) {
labelMargin.right = this.theme.label.smallMargin.right
} else {
labelMargin.right = this.theme.label.normalMargin.right
}
}
return labelMargin
}
private getLocalizedLabelMargin(): LocalizedMargin {
let localizedLabelMargin: LocalizedMargin = { start: LengthMetrics.vp(0), end: LengthMetrics.vp(0) }
if (this.label?.localizedLabelMargin?.start?.value !== void (0) &&
this.lengthMetricsToVp(this.label.localizedLabelMargin.start) >= 0) {
localizedLabelMargin.start = this.label?.localizedLabelMargin?.start
} else if ((this.prefixSymbol?.normal || this.prefixSymbol?.activated) || this.prefixIcon?.src) {
if (this.isChipSizeEnum() && this.chipSize == ChipSize.SMALL) {
localizedLabelMargin.start = this.theme.label.localizedSmallMargin.start
} else {
localizedLabelMargin.start = this.theme.label.localizedNormalMargin.start
}
}
if (this.label?.localizedLabelMargin?.end?.value !== void (0) &&
this.lengthMetricsToVp(this.label.localizedLabelMargin.end) >= 0) {
localizedLabelMargin.end = this.label?.localizedLabelMargin?.end
} else if ((this.suffixSymbol?.normal || this.suffixSymbol?.activated) ||
this.suffixIcon?.src || this.useDefaultSuffixIcon || this.isShowCloseIconMargin()) {
if (this.isChipSizeEnum() && this.chipSize == ChipSize.SMALL) {
localizedLabelMargin.end = this.theme.label.localizedSmallMargin.end
} else {
localizedLabelMargin.end = this.theme.label.localizedNormalMargin.end
}
}
return localizedLabelMargin
}
private getLabelStartEndVp(): LocalizedMargin {
let labelMargin: LocalizedMargin = this.getLocalizedLabelMargin()
if (this.label && (this.label.labelMargin !== void (0)) && (this.label.localizedLabelMargin === void (0))) {
let margin: Margin = this.getLabelMargin()
return {
start: LengthMetrics.vp(this.toVp(margin.left)),
end: LengthMetrics.vp(this.toVp(margin.right))
}
}
return {
start: LengthMetrics.vp(this.lengthMetricsToVp(labelMargin.start)),
end: LengthMetrics.vp(this.lengthMetricsToVp(labelMargin.end))
}
}
private getActualLabelMargin(): Margin | LocalizedMargin {
let localizedLabelMargin: LocalizedMargin = this.getLocalizedLabelMargin()
if (this.label && this.label.localizedLabelMargin !== void (0)) {
return localizedLabelMargin
}
if (this.label && this.label.labelMargin !== void (0)) {
return this.getLabelMargin()
}
return localizedLabelMargin
}
private getSuffixIconSize(): SizeOptions {
let suffixIconSize: SizeOptions = { width: 0, height: 0 }
if (this.suffixIcon?.size?.width !== void (0) && this.toVp(this.suffixIcon?.size?.width) >= 0) {
suffixIconSize.width = this.suffixIcon?.size?.width
} else {
if (this.getSuffixIconSrc()) {
suffixIconSize.width = this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL ?
this.theme.suffixIcon.smallSize.width : this.theme.suffixIcon.normalSize.width;
} else {
suffixIconSize.width = 0
}
}
if (this.suffixIcon?.size?.height !== void (0) && this.toVp(this.suffixIcon?.size?.height) >= 0) {
suffixIconSize.height = this.suffixIcon?.size?.height
} else {
if (this.getSuffixIconSrc()) {
suffixIconSize.height = this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL ?
this.theme.suffixIcon.smallSize.height : this.theme.suffixIcon.normalSize.height;
} else {
suffixIconSize.height = 0
}
}
return suffixIconSize
}
private getPrefixIconSize(): SizeOptions {
let prefixIconSize: SizeOptions = { width: 0, height: 0 }
if (this.prefixIcon?.size?.width !== void (0) && this.toVp(this.prefixIcon?.size?.width) >= 0) {
prefixIconSize.width = this.prefixIcon?.size?.width
} else {
if (this.prefixIcon?.src) {
prefixIconSize.width =
this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL ? this.theme.prefixIcon.smallSize.width :
this.theme.prefixIcon.normalSize.width;
} else {
prefixIconSize.width = 0
}
}
if (this.prefixIcon?.size?.height !== void (0) && this.toVp(this.prefixIcon?.size?.height) >= 0) {
prefixIconSize.height = this.prefixIcon?.size?.height
} else {
if (this.prefixIcon?.src) {
prefixIconSize.height =
this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL ? this.theme.prefixIcon.smallSize.height :
this.theme.prefixIcon.normalSize.height;
} else {
prefixIconSize.height = 0
}
}
return prefixIconSize
}
private getDefaultActiveIconColor(iconType: string): ResourceColor {
if (iconType === IconType.PREFIX_ICON) {
return this.chipNodeOnFocus ? this.theme.prefixIcon.focusActivatedColor :
this.theme.prefixIcon.activatedFillColor;
} else {
return this.chipNodeOnFocus ? this.theme.suffixIcon.focusActivatedColor :
this.theme.suffixIcon.activatedFillColor;
}
}
private getDefaultFillIconColor(iconType: string): ResourceColor {
if (iconType === IconType.PREFIX_ICON) {
return this.chipNodeOnFocus ? this.theme.prefixIcon.focusFillColor : this.theme.prefixIcon.fillColor;
} else {
return this.chipNodeOnFocus ? this.theme.suffixIcon.focusFillColor : this.theme.suffixIcon.fillColor;
}
}
private getSymbolActiveColor(iconType?: string): Array<ResourceColor> {
if (iconType === IconType.PREFIX_SYMBOL) {
return this.getColorArray(this.prefixIcon?.activatedFillColor,
this.theme.prefixIcon.focusActivatedColor, this.theme.prefixIcon.activatedFillColor);
} else if (iconType === IconType.SUFFIX_SYMBOL) {
return this.getColorArray(this.suffixIcon?.activatedFillColor,
this.theme.suffixIcon.focusActivatedColor, this.theme.suffixIcon.activatedFillColor);
} else {
return this.theme.defaultSymbol.activatedFontColor;
}
}
private getSymbolFillColor(iconType?: string): Array<ResourceColor> {
if (iconType === IconType.PREFIX_SYMBOL) {
return this.getColorArray(this.prefixIcon?.fillColor,
this.theme.prefixIcon.focusFillColor, this.theme.prefixIcon.fillColor);
} else if (iconType === IconType.SUFFIX_SYMBOL) {
return this.getColorArray(this.suffixIcon?.fillColor,
this.theme.suffixIcon.focusFillColor, this.theme.suffixIcon.fillColor);
} else {
return this.theme.defaultSymbol.normalFontColor;
}
}
private getColorArray(userDefined: ResourceColor | undefined, focusColor: ResourceColor,
normalColor: ResourceColor): Array<ResourceColor> {
if (userDefined) {
return [userDefined];
}
return this.chipNodeOnFocus ? [focusColor] : [normalColor];
}
private getPrefixIconFilledColor(): ResourceColor {
if (this.getChipActive()) {
return this.prefixIcon?.activatedFillColor ?? this.getDefaultActiveIconColor(IconType.PREFIX_ICON);
}
return this.prefixIcon?.fillColor ?? this.getDefaultFillIconColor(IconType.PREFIX_ICON);
}
private getSuffixIconFilledColor(): ResourceColor {
if (this.getChipActive()) {
return this.suffixIcon?.activatedFillColor ?? this.getDefaultActiveIconColor(IconType.SUFFIX_ICON);
}
return this.suffixIcon?.fillColor ?? this.getDefaultFillIconColor(IconType.SUFFIX_ICON);
}
private getDefaultSymbolColor(iconType?: string): Array<ResourceColor> {
if (this.getChipActive()) {
return this.getSymbolActiveColor(iconType);
}
return this.getSymbolFillColor(iconType);
}
private getPrefixSymbolModifier(): SymbolGlyphModifier | undefined {
if (this.getChipActive()) {
return this.prefixSymbol?.activated
}
return this.prefixSymbol?.normal
}
private getSuffixSymbolModifier(): SymbolGlyphModifier | undefined {
if (this.getChipActive()) {
return this.suffixSymbol?.activated
}
return this.suffixSymbol?.normal
}
private getSuffixIconFocusable(): boolean {
return !this.isSuffixIconFocusStyleCustomized && ((this.useDefaultSuffixIcon && (this.allowClose ?? true)) ||
this.suffixIcon?.action !== void (0));
}
private getChipNodePadding(): LocalizedPadding {
return (this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL) ? this.theme.chipNode.localizedSmallPadding :
this.theme.chipNode.localizedNormalPadding
}
private getChipNodeRadius(): Dimension {
if (this.chipNodeRadius !== void (0) && this.toVp(this.chipNodeRadius) >= 0) {
return this.chipNodeRadius as Dimension;
} else {
return ((this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL) ?
this.theme.chipNode.smallBorderRadius : this.theme.chipNode.normalBorderRadius);
}
}
private getChipNodeBackGroundColor(): ResourceColor {
let currentColor: ResourceColor;
let themeChipNode = this.theme.chipNode;
if (this.getChipActive()) {
currentColor =
(this.chipNodeOnFocus || this.isHover) && !this.isSetActiveChipBgColor() ? themeChipNode.focusActivatedBgColor :
this.chipNodeActivatedBackgroundColor ?? this.theme.chipNode.activatedBackgroundColor
} else {
currentColor =
(this.chipNodeOnFocus || this.isHover) && !this.isSetNormalChipBgColor() ? themeChipNode.focusBgColor :
this.chipNodeBackgroundColor ?? this.theme.chipNode.backgroundColor
}
let sourceColor: ColorMetrics;
try {
sourceColor = ColorMetrics.resourceColor(currentColor);
} catch (err) {
hilog.error(0x3900, 'Ace', `Chip resourceColor, error: ${err.toString()}`);
sourceColor = ColorMetrics.resourceColor(Color.Transparent);
}
if (!this.isShowPressedBackGroundColor) {
return sourceColor.color
}
return sourceColor
.blendColor(ColorMetrics.resourceColor("#19000000"))
.color
}
private getChipNodeHeight(): Length {
if (this.isChipSizeEnum()) {
return this.chipSize === ChipSize.SMALL ? this.theme.chipNode.smallHeight : this.theme.chipNode.normalHeight
} else {
this.chipNodeSize = this.chipSize as SizeOptions
return (this.chipNodeSize?.height !== void (0) && this.toVp(this.chipNodeSize?.height) >= 0) ?
this.toVp(this.chipNodeSize?.height) : this.theme.chipNode.normalHeight
}
}
private getLabelWidth(): number {
return px2vp(measure.measureText({
textContent: this.label?.text ?? "",
fontSize: this.getLabelFontSize(),
fontFamily: this.label?.fontFamily ?? this.theme.label.fontFamily,
fontWeight: this.getLabelFontWeight(),
maxLines: 1,
overflow: TextOverflow.Ellipsis,
textAlign: TextAlign.Center
}))
}
private getCalculateChipNodeWidth(): number {
let calWidth: number = 0
let startEndVp: LocalizedMargin = this.getLabelStartEndVp()
calWidth += this.getChipNodeBorderWidth() * 2;
calWidth += this.getChipNodePadding().start?.value ?? 0;
calWidth += this.toVp(this.getPrefixChipWidth())
calWidth += this.toVp(startEndVp.start?.value ?? 0)
calWidth += this.getLabelWidth()
calWidth += this.toVp(startEndVp.end?.value ?? 0)
calWidth += this.toVp(this.getSuffixChipWidth())
calWidth += this.getChipNodePadding().end?.value ?? 0
return calWidth
}
private getPrefixChipWidth(): Length | undefined {
if (this.prefixSymbol?.normal || this.prefixSymbol?.activated) {
return this.prefixSymbolWidth
} else if (this.prefixIcon?.src) {
return this.getPrefixIconSize().width
} else {
return 0
}
}
private getSuffixChipWidth(): Length | undefined {
if (this.suffixSymbol?.normal || this.suffixSymbol?.activated) {
return this.suffixSymbolWidth
} else if (this.suffixIcon?.src) {
return this.getSuffixIconSize().width
} else if (!this.suffixIcon?.src && (this.allowClose ?? true)) {
return this.allowCloseSymbolWidth
} else {
return 0
}
}
private getReserveChipNodeWidth(): number {
return this.getCalculateChipNodeWidth() - this.getLabelWidth() + (this.theme.chipNode.minLabelWidth as number)
}
private getChipEnable(): boolean {
return this.chipEnabled || this.chipEnabled === void (0)
}
private getChipActive(): boolean {
if (typeof this.chipActivated === 'undefined') {
return false
}
return this.chipActivated
}
private getChipNodeOpacity(): number {
return this.chipOpacity
}
private handleTouch(event: TouchEvent) {
if (!this.getChipEnable()) {
return
}
if (this.isHover) {
if (event.type === TouchType.Down || event.type === TouchType.Move) {
this.isShowPressedBackGroundColor = true
} else if (event.type === TouchType.Up) {
this.isShowPressedBackGroundColor = false
} else {
this.isShowPressedBackGroundColor = false
}
} else {
if (event.type === TouchType.Down || event.type === TouchType.Move) {
this.isShowPressedBackGroundColor = true
} else if (event.type === TouchType.Up) {
this.isShowPressedBackGroundColor = false
} else {
this.isShowPressedBackGroundColor = false
}
}
}
private hoverAnimate(isHover: boolean) {
if (!this.getChipEnable()) {
return
}
this.isHover = isHover
if (this.isHover) {
this.isShowPressedBackGroundColor = true
} else {
this.isShowPressedBackGroundColor = false
}
}
private deleteChipNodeAnimate() {
animateTo({ duration: 150, curve: Curve.Sharp }, () => {
this.chipOpacity = 0
this.chipBlendColor = Color.Transparent
})
animateTo({
duration: 150, curve: Curve.FastOutLinearIn, onFinish: () => {
this.deleteChip = true
}
},
() => {
this.chipScale = { x: 0.85, y: 0.85 }
})
}
private getSuffixIconSrc(): ResourceStr | undefined {
this.useDefaultSuffixIcon = !this.suffixIcon?.src && (this.allowClose ?? true)
return this.useDefaultSuffixIcon ? this.theme.suffixIcon.defaultDeleteIcon : (this.suffixIcon?.src ?? void (0))
}
private getChipNodeWidth(): Length {
if (!this.isChipSizeEnum()) {
this.chipNodeSize = this.chipSize as SizeOptions
if (this.chipNodeSize?.width !== void (0) && this.toVp(this.chipNodeSize.width) >= 0) {
return this.toVp(this.chipNodeSize.width)
}
}
let constraintWidth: ConstraintSizeOptions = this.getChipConstraintWidth()
return Math.min(Math.max(this.getCalculateChipNodeWidth(),
constraintWidth.minWidth as number), constraintWidth.maxWidth as number);
}
private getFocusOverlaySize(): SizeOptions {
return {
width: Math.max(this.getChipNodeWidth() as number, this.getChipConstraintWidth().minWidth as number) + 8,
height: this.getChipNodeHeight() as number + 8
}
}
private getChipConstraintWidth(): ConstraintSizeOptions {
let calcMinWidth: number = this.getReserveChipNodeWidth()
let constraintWidth: number = this.getCalculateChipNodeWidth()
let constraintSize: ConstraintSizeOptions
switch (this.chipBreakPoints) {
case BreakPointsType.SM:
constraintSize = {
minWidth: calcMinWidth,
maxWidth: Math.min(constraintWidth, this.theme.chipNode.breakPointConstraintWidth.breakPointSmMaxWidth)
}
break
case BreakPointsType.MD:
constraintSize = {
minWidth: Math.max(constraintWidth, this.theme.chipNode.breakPointConstraintWidth.breakPointMinWidth),
maxWidth: Math.min(constraintWidth, this.theme.chipNode.breakPointConstraintWidth.breakPointMdMaxWidth)
}
break
case BreakPointsType.LG:
constraintSize = {
minWidth: Math.max(constraintWidth, this.theme.chipNode.breakPointConstraintWidth.breakPointMinWidth),
maxWidth: Math.min(constraintWidth, this.theme.chipNode.breakPointConstraintWidth.breakPointLgMaxWidth)
}
break
default:
constraintSize = { minWidth: calcMinWidth, maxWidth: constraintWidth }
break
}
constraintSize.minWidth = Math.min(Math.max(this.getCalculateChipNodeWidth(),
constraintSize.minWidth as number), constraintSize.maxWidth as number)
constraintSize.minHeight = this.getChipNodeHeight()
if (!this.isChipSizeEnum() && this.chipNodeSize?.height !== void (0) && this.toVp(this.chipNodeSize?.height) >= 0) {
constraintSize.maxHeight = this.toVp(this.chipNodeSize.height)
constraintSize.minHeight = this.toVp(this.chipNodeSize.height)
}
if (!this.isChipSizeEnum() && this.chipNodeSize?.width !== void (0) && this.toVp(this.chipNodeSize?.width) >= 0) {
constraintSize.minWidth = this.toVp(this.chipNodeSize.width)
constraintSize.maxWidth = this.toVp(this.chipNodeSize.width)
} else if (this.toVp(this.fontSizeScale) >= this.theme.chipNode.suitAgeScale) {
constraintSize.minWidth = void (0)
constraintSize.maxWidth = void (0)
}
return constraintSize
}
@Builder
focusOverlay() {
Stack() {
if (this.chipNodeOnFocus && !this.suffixIconOnFocus) {
Stack()
.direction(this.chipDirection)
.borderRadius(this.toVp(this.getChipNodeRadius()) + 4)
.size(this.getFocusOverlaySize())
.borderColor(this.theme.chipNode.focusOutlineColor)
.borderWidth(this.theme.chipNode.borderWidth)
}
}
.direction(this.chipDirection)
.size({ width: 1, height: 1 })
.align(Alignment.Center)
}
@Styles
suffixIconFocusStyles() {
.borderColor(this.theme.chipNode.focusOutlineColor)
.borderWidth(this.getSuffixIconFocusable() ? this.theme.chipNode.borderWidth : 0)
}
@Styles
suffixIconNormalStyles() {
.borderColor(Color.Transparent)
.borderWidth(0)
}
aboutToAppear() {
let uiContent: UIContext = this.getUIContext();
this.fontSizeScale = (uiContent.getHostContext() as common.UIAbilityContext)?.config?.fontSizeScale ?? 1;
this.smListener.on("change", (mediaQueryResult: mediaquery.MediaQueryResult) => {
if (mediaQueryResult.matches) {
this.chipBreakPoints = BreakPointsType.SM
}
})
this.mdListener.on("change", (mediaQueryResult: mediaquery.MediaQueryResult) => {
if (mediaQueryResult.matches) {
this.chipBreakPoints = BreakPointsType.MD
}
})
this.lgListener.on("change", (mediaQueryResult: mediaquery.MediaQueryResult) => {
if (mediaQueryResult.matches) {
this.chipBreakPoints = BreakPointsType.LG
}
})
this.callbackId = this.getUIContext()
.getHostContext()
?.getApplicationContext()
?.on('environment', this.callbacks);
}
private getVisibility(): Visibility {
if (this.toVp(this.getChipNodeHeight()) > 0) {
return Visibility.Visible
} else {
return Visibility.None
}
}
private isSetActiveChipBgColor(): boolean {
if (!this.chipNodeActivatedBackgroundColor) {
return false;
}
try {
return ColorMetrics.resourceColor(this.chipNodeActivatedBackgroundColor).color !==
ColorMetrics.resourceColor(this.theme.chipNode.activatedBackgroundColor).color;
} catch (error) {
console.error(`[Chip] failed to get resourceColor`);
return false;
}
}
private isSetNormalChipBgColor(): boolean {
if (!this.chipNodeBackgroundColor) {
return false;
}
try {
return ColorMetrics.resourceColor(this.chipNodeBackgroundColor).color !==
ColorMetrics.resourceColor(this.theme.chipNode.backgroundColor).color;
} catch (error) {
console.error(`[Chip] failed to get resourceColor`);
return false;
}
}
private getShadowStyles(): ShadowStyle | undefined {
if (!this.chipNodeOnFocus) {
return undefined;
}
return this.resourceToNumber(this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL ?
this.theme.chipNode.smallShadowStyle :
this.theme.chipNode.normalShadowStyle, -1) as ShadowStyle;
}
aboutToDisappear() {
this.smListener.off("change")
this.mdListener.off("change")
this.lgListener.off("change")
if (this.callbackId) {
this.getUIContext()
?.getHostContext()
?.getApplicationContext()
?.off('environment', this.callbackId);
this.callbackId = void (0)
}
}
@Builder
chipBuilder() {
Button() {
Row() {
if (this.prefixSymbol?.normal || this.prefixSymbol?.activated) {
SymbolGlyph()
.fontSize(this.defaultSymbolFontsize())
.fontColor(this.getDefaultSymbolColor(IconType.PREFIX_SYMBOL))
.attributeModifier(this.getPrefixSymbolModifier())
.effectStrategy(SymbolEffectStrategy.NONE)
.symbolEffect(this.symbolEffect, false)
.symbolEffect(this.symbolEffect, this.theme.defaultSymbol.defaultEffect)
.onSizeChange((oldValue, newValue) => {
this.prefixSymbolWidth = newValue?.width
})
.key('PrefixSymbolGlyph')
} else if (this.prefixIcon?.src !== "") {
Image(this.prefixIcon?.src)
.direction(this.chipDirection)
.opacity(this.getChipNodeOpacity())
.size(this.getPrefixIconSize())
.fillColor(this.getPrefixIconFilledColor())
.enabled(this.getChipEnable())
.objectFit(ImageFit.Cover)
.focusable(false)
.flexShrink(0)
.visibility(this.getVisibility())
.draggable(false)
}
Text(this.label?.text ?? "")
.direction(this.chipDirection)
.opacity(this.getChipNodeOpacity())
.fontSize(this.getLabelFontSize())
.fontColor(this.getLabelFontColor())
.fontFamily(this.getLabelFontFamily())
.fontWeight(this.getLabelFontWeight())
.margin(this.getActualLabelMargin())
.enabled(this.getChipEnable())
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.flexShrink(1)
.focusable(true)
.textAlign(TextAlign.Center)
.visibility(this.getVisibility())
.draggable(false)
if (this.suffixSymbol?.normal || this.suffixSymbol?.activated) {
Button({ type: ButtonType.Normal }) {
SymbolGlyph()
.fontSize(this.defaultSymbolFontsize())
.fontColor(this.getDefaultSymbolColor(IconType.SUFFIX_SYMBOL))
.attributeModifier(this.getSuffixSymbolModifier())
.effectStrategy(SymbolEffectStrategy.NONE)
.symbolEffect(this.symbolEffect, false)
.symbolEffect(this.symbolEffect, this.theme.defaultSymbol.defaultEffect)
.onSizeChange((oldValue, newValue) => {
this.suffixSymbolWidth = newValue?.width
})
.key('SuffixSymbolGlyph')
}
.onClick(this.getSuffixSymbolAction())
.accessibilityText(this.getSuffixSymbolAccessibilityText())
.accessibilityDescription(this.getSuffixSymbolAccessibilityDescription())
.accessibilityLevel(this.getSuffixSymbolAccessibilityLevel())
.backgroundColor(Color.Transparent)
.borderRadius(0)
.padding(0)
.stateEffect(false)
.focusable(!this.isSuffixIconFocusStyleCustomized)
.hoverEffect(this.setHoverEffect())
} else if (this.suffixIcon?.src !== "") {
Button({ type: ButtonType.Normal }) {
Image(this.getSuffixIconSrc())
.direction(this.chipDirection)
.opacity(this.getChipNodeOpacity())
.size(this.getSuffixIconSize())
.fillColor(this.getSuffixIconFilledColor())
.enabled(this.getChipEnable())
.objectFit(ImageFit.Cover)
.flexShrink(0)
.visibility(this.getVisibility())
.draggable(false)
.onFocus(() => {
this.suffixIconOnFocus = true
})
.onBlur(() => {
this.suffixIconOnFocus = false
})
}
.backgroundColor(Color.Transparent)
.borderRadius(0)
.padding(0)
.size(this.getSuffixIconSize())
.accessibilityText(this.getSuffixIconAccessibilityText())
.accessibilityDescription(this.getSuffixIconAccessibilityDescription())
.accessibilityLevel(this.getSuffixIconAccessibilityLevel())
.onClick(() => {
if (!this.getChipEnable()) {
return
}
if (this.suffixIcon?.action) {
this.suffixIcon.action()
return
}
if ((this.allowClose ?? true) && this.useDefaultSuffixIcon) {
this.onClose()
this.deleteChipNodeAnimate()
return
}
this.onClicked()
})
.focusable(this.getSuffixIconFocusable())
.hoverEffect(this.setHoverEffect())
.stateEffect(this.setPressEffect())
} else if (this.allowClose ?? true) {
Button({ type: ButtonType.Normal }) {
SymbolGlyph($r('sys.symbol.xmark'))
.fontSize(this.defaultSymbolFontsize())
.fontColor(this.getDefaultSymbolColor(IconType.SUFFIX_SYMBOL))
.onSizeChange((oldValue, newValue) => {
this.allowCloseSymbolWidth = newValue?.width
})
.key('AllowCloseSymbolGlyph')
}
.backgroundColor(Color.Transparent)
.borderRadius(0)
.padding(0)
.accessibilityText(this.getCloseIconAccessibilityText())
.accessibilityDescription(this.getCloseIconAccessibilityDescription())
.accessibilityLevel(this.getCloseIconAccessibilityLevel())
.onClick(() => {
if (!this.getChipEnable()) {
return
}
this.onClose()
this.deleteChipNodeAnimate()
})
.focusable(!this.isSuffixIconFocusStyleCustomized)
.hoverEffect(this.setHoverEffect())
.stateEffect(this.setPressEffect())
}
}
.direction(this.chipDirection)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)
.padding(this.getChipNodePadding())
.constraintSize(this.getChipConstraintWidth())
}
.constraintSize(this.getChipConstraintWidth())
.direction(this.chipDirection)
.type(ButtonType.Normal)
.clip(false)
.backgroundColor(this.getChipNodeBackGroundColor())
.borderRadius(this.getChipNodeRadius())
.borderWidth(this.getChipNodeBorderWidth())
.borderColor(this.getChipNodeBorderColor())
.enabled(this.getChipEnable())
.scale(this.chipScale)
.focusable(true)
.opacity(this.getChipNodeOpacity())
.shadow(this.getShadowStyles())
.padding(0)
.accessibilityGroup(true)
.accessibilityDescription(this.getAccessibilityDescription())
.accessibilityLevel(this.getAccessibilityLevel())
.accessibilityChecked(this.getAccessibilityChecked())
.accessibilitySelected(this.getAccessibilitySelected())
.onFocus(() => {
this.chipNodeOnFocus = true
this.chipZoomIn();
})
.onBlur(() => {
this.chipNodeOnFocus = false
this.chipZoomOut();
})
.onTouch((event) => {
this.handleTouch(event)
})
.onHover((isHover: boolean) => {
if (isHover) {
this.isShowPressedBackGroundColor = true;
this.chipZoomIn();
} else {
if (!this.isShowPressedBackGroundColor && isHover) {
this.isShowPressedBackGroundColor = true
} else {
this.isShowPressedBackGroundColor = false
}
this.chipZoomOut();
}
this.isHover = isHover;
})
.onKeyEvent((event) => {
if (!event || event.type === null || event.type !== KeyType.Down) {
return;
}
let isDeleteChip = event.keyCode === KeyCode.KEYCODE_FORWARD_DEL &&
!this.suffixIconOnFocus;
let isEnterDeleteChip = event.keyCode === KeyCode.KEYCODE_ENTER && this.allowClose !== false &&
!this.suffixIcon?.src && this.isSuffixIconFocusStyleCustomized;
if (isDeleteChip || isEnterDeleteChip) {
this.deleteChipNodeAnimate();
}
})
.onClick(this.onClicked === noop ? undefined : this.onClicked.bind(this))
}
private setHoverEffect(): HoverEffect | undefined {
return this.isSuffixIconFocusStyleCustomized ? HoverEffect.None : undefined;
}
private setPressEffect(): boolean | undefined {
return this.isSuffixIconFocusStyleCustomized ? false : undefined;
}
private chipZoomOut() {
if (this.isSuffixIconFocusStyleCustomized) {
this.chipScale = {
x: 1, y: 1
};
}
}
private chipZoomIn() {
if (this.isSuffixIconFocusStyleCustomized) {
this.chipScale = {
x: this.resourceToNumber(this.theme.chipNode.focusBtnScaleX, 1),
y: this.resourceToNumber(this.theme.chipNode.focusBtnScaleY, 1),
};
}
}
getSuffixSymbolAccessibilityLevel(): string {
if (this.getChipActive()) {
if (this.suffixSymbolOptions?.activatedAccessibility?.accessibilityLevel === 'no' ||
this.suffixSymbolOptions?.activatedAccessibility?.accessibilityLevel === 'no-hide-descendants') {
return this.suffixSymbolOptions.activatedAccessibility.accessibilityLevel;
}
return this.suffixSymbolOptions?.action ? 'yes' : 'no';
}
if (this.suffixSymbolOptions?.normalAccessibility?.accessibilityLevel === 'no' ||
this.suffixSymbolOptions?.normalAccessibility?.accessibilityLevel === 'no-hide-descendants') {
return this.suffixSymbolOptions.normalAccessibility.accessibilityLevel;
}
return this.suffixSymbolOptions?.action ? 'yes' : 'no';
}
getSuffixSymbolAccessibilityDescription(): Resource | undefined {
if (this.getChipActive()) {
if (typeof this.suffixSymbolOptions?.activatedAccessibility?.accessibilityDescription !== 'undefined') {
return this.suffixSymbolOptions.activatedAccessibility.accessibilityDescription as Resource;
}
return undefined;
}
if (typeof this.suffixSymbolOptions?.normalAccessibility?.accessibilityDescription !== 'undefined') {
return this.suffixSymbolOptions.normalAccessibility.accessibilityDescription as Resource;
}
return undefined;
}
getSuffixSymbolAccessibilityText(): Resource | undefined {
if (this.getChipActive()) {
if (typeof this.suffixSymbolOptions?.activatedAccessibility?.accessibilityText !== 'undefined') {
return this.suffixSymbolOptions.activatedAccessibility.accessibilityText as Resource;
}
return undefined;
}
if (typeof this.suffixSymbolOptions?.normalAccessibility?.accessibilityText !== 'undefined') {
return this.suffixSymbolOptions.normalAccessibility.accessibilityText as Resource;
}
return undefined;
}
getSuffixSymbolAction(): Callback<ClickEvent> | undefined {
if (typeof this.suffixSymbolOptions?.action === 'undefined') {
return undefined;
}
return () => {
if (!this.getChipEnable()) {
return;
}
this.suffixSymbolOptions?.action?.();
};
}
private getAccessibilitySelected(): boolean | undefined {
if (this.getChipAccessibilitySelectedType() === AccessibilitySelectedType.SELECTED) {
return this.getChipActive();
}
return undefined;
}
private getAccessibilityChecked(): boolean | undefined {
if (this.getChipAccessibilitySelectedType() === AccessibilitySelectedType.CHECKED) {
return this.getChipActive();
}
return undefined;
}
private getChipAccessibilitySelectedType(): AccessibilitySelectedType {
if (typeof this.chipActivated === 'undefined') {
return AccessibilitySelectedType.CLICKED;
}
return this.chipAccessibilitySelectedType ?? AccessibilitySelectedType.CHECKED;
}
private getCloseIconAccessibilityLevel(): string {
if (this.closeOptions?.accessibilityLevel === 'no' || this.closeOptions?.accessibilityLevel === 'no-hide-descendants') {
return this.closeOptions.accessibilityLevel;
}
return 'yes';
}
private getCloseIconAccessibilityDescription(): Resource | undefined {
if (typeof this.closeOptions?.accessibilityDescription === 'undefined') {
return undefined;
}
return this.closeOptions.accessibilityDescription as Resource;
}
private getCloseIconAccessibilityText(): Resource {
if (typeof this.closeOptions?.accessibilityText === 'undefined') {
return $r('sys.string.delete_used_for_accessibility_text')
}
return this.closeOptions.accessibilityText as ESObject as Resource;
}
private getSuffixIconAccessibilityLevel(): string {
if (this.suffixIcon?.accessibilityLevel === 'no' || this.suffixIcon?.accessibilityLevel === 'no-hide-descendants') {
return this.suffixIcon.accessibilityLevel;
}
return this.suffixIcon?.action ? 'yes' : 'no';
}
private getSuffixIconAccessibilityDescription(): Resource | undefined {
if (typeof this.suffixIcon?.accessibilityDescription === 'undefined') {
return undefined;
}
return this.suffixIcon.accessibilityDescription as ESObject as Resource;
}
private getSuffixIconAccessibilityText(): Resource | undefined {
if (typeof this.suffixIcon?.accessibilityText === 'undefined') {
return undefined;
}
return this.suffixIcon.accessibilityText as ESObject as Resource;
}
private getAccessibilityLevel(): string | undefined {
return this.chipAccessibilityLevel;
}
private getAccessibilityDescription(): Resource | undefined {
if (typeof this.chipAccessibilityDescription === 'undefined') {
return undefined;
}
return this.chipAccessibilityDescription as ESObject as Resource;
}
resourceToNumber(resource: Resource, defaultValue: number): number {
if (!resource || !resource.type) {
console.error('[Chip] failed: resource get fail.');
return defaultValue;
}
const resourceManager = this.getUIContext().getHostContext()?.resourceManager;
if (!resourceManager) {
console.error('[Chip] failed to get resourceManager.');
return defaultValue;
}
switch (resource.type) {
case RESOURCE_TYPE_FLOAT:
case RESOURCE_TYPE_INTEGER:
try {
if (resource.id !== -1) {
return resourceManager.getNumber(resource);
}
return resourceManager.getNumberByName((resource.params as string[])[0].split('.')[2]);
} catch (error) {
console.error(`[Chip] get resource error, return defaultValue`);
return defaultValue;
}
default:
return defaultValue;
}
}
build() {
if (!this.deleteChip) {
this.chipBuilder()
}
}
}