1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { KeyCode } from '@ohos.multimodalInput.keyCode'; 17import measure from '@ohos.measure'; 18import mediaquery from '@ohos.mediaquery'; 19import resourceManager from '@ohos.resourceManager'; 20import { ColorMetrics, LengthMetrics, LengthUnit } from '@ohos.arkui.node'; 21import EnvironmentCallback from '@ohos.app.ability.EnvironmentCallback'; 22import { SymbolGlyphModifier } from '@ohos.arkui.modifier'; 23import componentUtils from '@ohos.arkui.componentUtils'; 24import hilog from '@ohos.hilog'; 25import common from '@ohos.app.ability.common'; 26 27const RESOURCE_TYPE_STRING = 10003; 28const RESOURCE_TYPE_FLOAT = 10002; 29const RESOURCE_TYPE_INTEGER = 10007; 30 31export enum ChipSize { 32 NORMAL = "NORMAL", 33 SMALL = "SMALL" 34} 35 36enum BreakPointsType { 37 SM = "SM", 38 MD = "MD", 39 LG = "LG" 40} 41 42export enum AccessibilitySelectedType { 43 CLICKED = 0, 44 CHECKED = 1, 45 SELECTED = 2, 46} 47 48export interface IconCommonOptions { 49 src: ResourceStr; 50 size?: SizeOptions; 51 fillColor?: ResourceColor; 52 activatedFillColor?: ResourceColor; 53} 54 55export interface SuffixIconOptions extends IconCommonOptions { 56 action?: () => void; 57 accessibilityText?: ResourceStr; 58 accessibilityDescription?: ResourceStr; 59 accessibilityLevel?: string; 60} 61 62export interface PrefixIconOptions extends IconCommonOptions {} 63 64export interface AccessibilityOptions { 65 accessibilityLevel?: string; 66 accessibilityText?: ResourceStr; 67 accessibilityDescription?: ResourceStr; 68} 69 70export interface CloseOptions extends AccessibilityOptions {} 71 72export interface ChipSymbolGlyphOptions { 73 normal?: SymbolGlyphModifier; 74 activated?: SymbolGlyphModifier; 75} 76 77export interface ChipSuffixSymbolGlyphOptions { 78 normalAccessibility?: AccessibilityOptions; 79 activatedAccessibility?: AccessibilityOptions; 80 action?: VoidCallback; 81} 82 83export interface LabelMarginOptions { 84 left?: Dimension; 85 right?: Dimension; 86} 87 88export interface LocalizedLabelMarginOptions { 89 start?: LengthMetrics; 90 end?: LengthMetrics; 91} 92 93export interface LabelOptions { 94 text: string; 95 fontSize?: Dimension; 96 fontColor?: ResourceColor; 97 activatedFontColor?: ResourceColor; 98 fontFamily?: string; 99 labelMargin?: LabelMarginOptions; 100 localizedLabelMargin?: LocalizedLabelMarginOptions; 101} 102 103interface IconTheme { 104 size: SizeOptions; 105 fillColor: ResourceColor; 106 activatedFillColor: ResourceColor; 107} 108 109interface PrefixIconTheme extends IconTheme {} 110 111interface SuffixIconTheme extends IconTheme { 112 defaultDeleteIcon: ResourceStr; 113 focusable: boolean; 114} 115 116interface DefaultSymbolTheme { 117 normalFontColor: Array<ResourceColor>; 118 activatedFontColor: Array<ResourceColor>; 119 fontSize: Length; 120 defaultEffect: number; 121} 122 123interface LabelTheme { 124 normalFontSize: Dimension; 125 smallFontSize: Dimension; 126 fontColor: ResourceColor; 127 activatedFontColor: ResourceColor; 128 fontFamily: string; 129 normalMargin: Margin; 130 localizedNormalMargin: LocalizedMargin; 131 smallMargin: Margin; 132 localizedSmallMargin: LocalizedMargin; 133 defaultFontSize: Dimension; 134} 135 136interface ChipNodeOpacity { 137 normal: number; 138 hover: number; 139 pressed: number; 140} 141 142interface ChipNodeConstraintWidth { 143 breakPointMinWidth: number, 144 breakPointSmMaxWidth: number, 145 breakPointMdMaxWidth: number, 146 breakPointLgMaxWidth: number, 147} 148 149interface ChipNodeTheme { 150 suitAgeScale: number; 151 minLabelWidth: Dimension; 152 normalHeight: Dimension; 153 smallHeight: Dimension; 154 enabled: boolean; 155 activated: boolean; 156 backgroundColor: ResourceColor; 157 activatedBackgroundColor: ResourceColor; 158 focusOutlineColor: ResourceColor; 159 focusOutlineMargin: number; 160 normalBorderRadius: Dimension; 161 smallBorderRadius: Dimension; 162 borderWidth: number; 163 localizedNormalPadding: LocalizedPadding; 164 localizedSmallPadding: LocalizedPadding; 165 hoverBlendColor: ResourceColor; 166 pressedBlendColor: ResourceColor; 167 opacity: ChipNodeOpacity; 168 breakPointConstraintWidth: ChipNodeConstraintWidth; 169} 170 171interface ChipTheme { 172 prefixIcon: PrefixIconTheme; 173 label: LabelTheme; 174 suffixIcon: SuffixIconTheme; 175 defaultSymbol: DefaultSymbolTheme; 176 chipNode: ChipNodeTheme; 177} 178 179export const defaultTheme: ChipTheme = { 180 prefixIcon: { 181 size: { width: 16, height: 16 }, 182 fillColor: $r('sys.color.ohos_id_color_secondary'), 183 activatedFillColor: $r('sys.color.ohos_id_color_text_primary_contrary'), 184 }, 185 label: { 186 normalFontSize: $r('sys.float.ohos_id_text_size_button2'), 187 smallFontSize: $r('sys.float.ohos_id_text_size_button2'), 188 fontColor: $r('sys.color.ohos_id_color_text_primary'), 189 activatedFontColor: $r('sys.color.ohos_id_color_text_primary_contrary'), 190 fontFamily: "HarmonyOS Sans", 191 normalMargin: { 192 left: 6, 193 right: 6, 194 top: 0, 195 bottom: 0 196 }, 197 smallMargin: { 198 left: 4, 199 right: 4, 200 top: 0, 201 bottom: 0 202 }, 203 defaultFontSize: 14, 204 localizedNormalMargin: { 205 start: LengthMetrics.vp(6), 206 end: LengthMetrics.vp(6), 207 top: LengthMetrics.vp(0), 208 bottom: LengthMetrics.vp(0) 209 }, 210 localizedSmallMargin: { 211 start: LengthMetrics.vp(4), 212 end: LengthMetrics.vp(4), 213 top: LengthMetrics.vp(0), 214 bottom: LengthMetrics.vp(0), 215 } 216 }, 217 suffixIcon: { 218 size: { width: 16, height: 16 }, 219 fillColor: $r('sys.color.ohos_id_color_secondary'), 220 activatedFillColor: $r('sys.color.ohos_id_color_text_primary_contrary'), 221 defaultDeleteIcon: $r('sys.media.ohos_ic_public_cancel', 16, 16), 222 focusable: false, 223 }, 224 defaultSymbol: { 225 normalFontColor: [$r('sys.color.ohos_id_color_secondary')], 226 activatedFontColor: [$r('sys.color.ohos_id_color_text_primary_contrary')], 227 fontSize: 16, 228 defaultEffect: -1, 229 }, 230 chipNode: { 231 suitAgeScale: 1.75, 232 minLabelWidth: 12, 233 normalHeight: 36, 234 smallHeight: 28, 235 enabled: true, 236 activated: false, 237 backgroundColor: $r('sys.color.ohos_id_color_button_normal'), 238 activatedBackgroundColor: $r('sys.color.ohos_id_color_emphasize'), 239 focusOutlineColor: $r('sys.color.ohos_id_color_focused_outline'), 240 focusOutlineMargin: 2, 241 normalBorderRadius: $r('sys.float.ohos_id_corner_radius_tips_instant_tip'), 242 smallBorderRadius: $r('sys.float.ohos_id_corner_radius_piece'), 243 borderWidth: 2, 244 localizedNormalPadding: { 245 start: LengthMetrics.vp(16), 246 end: LengthMetrics.vp(16), 247 top: LengthMetrics.vp(4), 248 bottom: LengthMetrics.vp(4) 249 }, 250 localizedSmallPadding: { 251 start: LengthMetrics.vp(12), 252 end: LengthMetrics.vp(12), 253 top: LengthMetrics.vp(4), 254 bottom: LengthMetrics.vp(4) 255 }, 256 hoverBlendColor: $r('sys.color.ohos_id_color_hover'), 257 pressedBlendColor: $r('sys.color.ohos_id_color_click_effect'), 258 opacity: { normal: 1, hover: 0.95, pressed: 0.9 }, 259 breakPointConstraintWidth: { 260 breakPointMinWidth: 128, 261 breakPointSmMaxWidth: 156, 262 breakPointMdMaxWidth: 280, 263 breakPointLgMaxWidth: 400 264 } 265 } 266}; 267 268const noop = () => { 269}; 270 271interface ChipOptions { 272 prefixIcon?: PrefixIconOptions; 273 prefixSymbol?: ChipSymbolGlyphOptions; 274 label: LabelOptions; 275 suffixIcon?: SuffixIconOptions; 276 suffixSymbol?: ChipSymbolGlyphOptions; 277 suffixSymbolOptions?: ChipSuffixSymbolGlyphOptions; 278 allowClose?: boolean; 279 closeOptions?: CloseOptions; 280 enabled?: boolean; 281 activated?: boolean; 282 backgroundColor?: ResourceColor; 283 activatedBackgroundColor?: ResourceColor; 284 borderRadius?: Dimension; 285 size?: ChipSize | SizeOptions; 286 direction?: Direction; 287 accessibilitySelectedType?: AccessibilitySelectedType; 288 accessibilityDescription?: ResourceStr; 289 accessibilityLevel?: string; 290 onClose?: () => void 291 onClicked?: () => void 292} 293 294@Builder 295export function Chip(options: ChipOptions) { 296 ChipComponent({ 297 chipSize: options.size, 298 prefixIcon: options.prefixIcon, 299 prefixSymbol: options.prefixSymbol, 300 label: options.label, 301 suffixIcon: options.suffixIcon, 302 suffixSymbol: options.suffixSymbol, 303 suffixSymbolOptions: options.suffixSymbolOptions, 304 allowClose: options.allowClose, 305 closeOptions: options.closeOptions, 306 chipEnabled: options.enabled, 307 chipActivated: options.activated, 308 chipNodeBackgroundColor: options.backgroundColor, 309 chipNodeActivatedBackgroundColor: options.activatedBackgroundColor, 310 chipNodeRadius: options.borderRadius, 311 chipDirection: options.direction, 312 chipAccessibilitySelectedType: options.accessibilitySelectedType, 313 chipAccessibilityDescription: options.accessibilityDescription, 314 chipAccessibilityLevel: options.accessibilityLevel, 315 onClose: options.onClose, 316 onClicked: options.onClicked, 317 }) 318} 319 320function isValidString(dimension: string, regex: RegExp): boolean { 321 const matches = dimension.match(regex); 322 if (!matches || matches.length < 3) { 323 return false; 324 } 325 const value = Number.parseFloat(matches[1]); 326 return value >= 0; 327} 328 329function isValidDimensionString(dimension: string): boolean { 330 return isValidString(dimension, new RegExp('(-?\\d+(?:\\.\\d+)?)_?(fp|vp|px|lpx|%)?$', 'i')); 331} 332 333function isValidResource(context: Context | undefined, value: Resource) { 334 const resourceManager = context?.resourceManager; 335 if (value === void (0) || value === null || resourceManager === void (0)) { 336 return false; 337 } 338 if (value.type !== RESOURCE_TYPE_STRING && value.type !== RESOURCE_TYPE_INTEGER && 339 value.type !== RESOURCE_TYPE_FLOAT) { 340 return false; 341 } 342 343 if (value.type === RESOURCE_TYPE_INTEGER || value.type === RESOURCE_TYPE_FLOAT) { 344 if (resourceManager.getNumber(value.id) >= 0) { 345 return true; 346 } else { 347 return false; 348 } 349 } 350 351 if (value.type === RESOURCE_TYPE_STRING && !isValidDimensionString(resourceManager.getStringSync(value.id))) { 352 return false; 353 } else { 354 return true; 355 } 356} 357 358@Component 359export struct ChipComponent { 360 private theme: ChipTheme = defaultTheme; 361 @Prop chipSize: ChipSize | SizeOptions = ChipSize.NORMAL 362 @Prop allowClose: boolean = true 363 @Prop closeOptions?: CloseOptions 364 @Prop chipDirection: Direction = Direction.Auto 365 @Prop prefixIcon: PrefixIconOptions = { src: "" } 366 @Prop prefixSymbol: ChipSymbolGlyphOptions 367 @Prop label: LabelOptions = { text: "" } 368 @Prop suffixIcon: SuffixIconOptions = { src: "" } 369 @Prop suffixSymbol?: ChipSymbolGlyphOptions 370 @Prop suffixSymbolOptions?: ChipSuffixSymbolGlyphOptions 371 @Prop chipNodeBackgroundColor: ResourceColor = this.theme.chipNode.backgroundColor 372 @Prop chipNodeActivatedBackgroundColor: ResourceColor = this.theme.chipNode.activatedBackgroundColor 373 @Prop chipNodeRadius: Dimension | undefined = void (0) 374 @Prop chipEnabled: boolean = true 375 @Prop chipActivated?: boolean 376 @Prop chipAccessibilitySelectedType?: AccessibilitySelectedType 377 @Prop chipAccessibilityDescription?: ResourceStr 378 @Prop chipAccessibilityLevel?: string 379 @State isHover: boolean = false 380 @State chipScale: ScaleOptions = { x: 1, y: 1 } 381 @State chipOpacity: number = 1 382 @State chipBlendColor: ResourceColor = Color.Transparent 383 @State deleteChip: boolean = false 384 @State chipNodeOnFocus: boolean = false 385 @State useDefaultSuffixIcon: boolean = false 386 private chipNodeSize: SizeOptions = {} 387 private onClose: () => void = noop 388 private onClicked: () => void = noop 389 @State suffixIconOnFocus: boolean = false 390 @State chipBreakPoints: BreakPointsType = BreakPointsType.SM 391 private smListener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(0vp<width) and (width<600vp)') 392 private mdListener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(600vp<=width) and (width<840vp)') 393 private lgListener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(840vp<=width)') 394 @State private isShowPressedBackGroundColor: boolean = false 395 @State fontSizeScale: number | undefined = 0 396 @State fontWeightScale: number | undefined = 0 397 private callbacks: EnvironmentCallback = { 398 onConfigurationUpdated: (configuration) => { 399 this.fontSizeScale = configuration.fontSizeScale; 400 this.fontWeightScale = configuration.fontWeightScale; 401 }, onMemoryLevel() { 402 } 403 } 404 private callbackId: number | undefined = undefined 405 @State prefixSymbolWidth: Length | undefined = 406 this.toVp(componentUtils.getRectangleById('PrefixSymbolGlyph')?.size?.width); 407 @State suffixSymbolWidth: Length | undefined = 408 this.toVp(componentUtils.getRectangleById('SuffixSymbolGlyph')?.size?.width); 409 @State allowCloseSymbolWidth: Length | undefined = 410 this.toVp(componentUtils.getRectangleById('AllowCloseSymbolGlyph')?.size?.width); 411 @State symbolEffect: SymbolEffect = new SymbolEffect(); 412 413 private isChipSizeEnum(): boolean { 414 return typeof (this.chipSize) === 'string' 415 } 416 417 private getLabelFontSize(): Dimension { 418 if (this.label?.fontSize !== void (0) && this.toVp(this.label.fontSize) >= 0) { 419 return this.label.fontSize 420 } else { 421 if (this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL) { 422 try { 423 resourceManager.getSystemResourceManager() 424 .getNumberByName((((this.theme.label.smallFontSize as Resource).params as string[])[0]).split('.')[2]) 425 return this.theme.label.smallFontSize 426 } catch (error) { 427 return this.theme.label.defaultFontSize 428 } 429 } else { 430 try { 431 resourceManager.getSystemResourceManager() 432 .getNumberByName((((this.theme.label.normalFontSize as Resource).params as string[])[0]).split('.')[2]) 433 return this.theme.label.normalFontSize 434 } catch (error) { 435 return this.theme.label.defaultFontSize 436 } 437 } 438 } 439 } 440 441 private getLabelFontColor(): ResourceColor { 442 if (this.getChipActive()) { 443 return this.label?.activatedFontColor ?? this.theme.label.activatedFontColor 444 } 445 return this.label?.fontColor ?? this.theme.label.fontColor 446 } 447 448 private getLabelFontFamily(): string { 449 return this.label?.fontFamily ?? this.theme.label.fontFamily 450 } 451 452 private getLabelFontWeight(): FontWeight { 453 if (this.getChipActive()) { 454 return FontWeight.Medium 455 } 456 return FontWeight.Regular 457 } 458 459 private lengthMetricsToVp(lengthMetrics?: LengthMetrics): number { 460 let defaultValue: number = 0; 461 if (lengthMetrics) { 462 switch (lengthMetrics.unit) { 463 case LengthUnit.PX: 464 return px2vp(lengthMetrics.value) 465 case LengthUnit.VP: 466 return lengthMetrics.value 467 case LengthUnit.FP: 468 return px2vp(fp2px(lengthMetrics.value)) 469 case LengthUnit.PERCENT: 470 return Number.NEGATIVE_INFINITY 471 case LengthUnit.LPX: 472 return px2vp(lpx2px(lengthMetrics.value)) 473 } 474 } 475 return defaultValue; 476 } 477 478 private toVp(value: Dimension | Length | undefined): number { 479 if (value === void (0)) { 480 return Number.NEGATIVE_INFINITY 481 } 482 switch (typeof (value)) { 483 case 'number': 484 return value as number 485 case 'object': 486 try { 487 let returnValue = this.lengthMetricsToVp(LengthMetrics.resource(value)); 488 if (returnValue === 0 && 489 !isValidResource(getContext(this), value)) { 490 return Number.NEGATIVE_INFINITY; 491 } 492 return returnValue; 493 } catch (error) { 494 return Number.NEGATIVE_INFINITY 495 } 496 case 'string': 497 let regex: RegExp = new RegExp("(-?\\d+(?:\\.\\d+)?)_?(fp|vp|px|lpx|%)?$", "i"); 498 let matches: RegExpMatchArray | null = value.match(regex); 499 if (!matches) { 500 return Number.NEGATIVE_INFINITY 501 } 502 let length: number = Number(matches?.[1] ?? 0); 503 let unit: string = matches?.[2] ?? 'vp' 504 switch (unit.toLowerCase()) { 505 case 'px': 506 length = px2vp(length) 507 break 508 case 'fp': 509 length = px2vp(fp2px(length)) 510 break 511 case 'lpx': 512 length = px2vp(lpx2px(length)) 513 break 514 case '%': 515 length = Number.NEGATIVE_INFINITY 516 break 517 case 'vp': 518 break 519 default: 520 break 521 } 522 return length 523 default: 524 return Number.NEGATIVE_INFINITY 525 } 526 } 527 528 private getLabelMargin(): Margin { 529 let labelMargin: Margin = { left: 0, right: 0 } 530 if (this.label?.labelMargin?.left !== void (0) && this.toVp(this.label.labelMargin.left) >= 0) { 531 labelMargin.left = this.label?.labelMargin?.left 532 } else if ((this.prefixSymbol?.normal || this.prefixSymbol?.activated) || this.prefixIcon?.src) { 533 if (this.isChipSizeEnum() && this.chipSize == ChipSize.SMALL) { 534 labelMargin.left = this.theme.label.smallMargin.left 535 } else { 536 labelMargin.left = this.theme.label.normalMargin.left 537 } 538 } 539 if (this.label?.labelMargin?.right !== void (0) && this.toVp(this.label.labelMargin.right) >= 0) { 540 labelMargin.right = this.label?.labelMargin?.right 541 } else if ((this.suffixSymbol?.normal || this.suffixSymbol?.activated) || 542 this.suffixIcon?.src || this.useDefaultSuffixIcon) { 543 if (this.isChipSizeEnum() && this.chipSize == ChipSize.SMALL) { 544 labelMargin.right = this.theme.label.smallMargin.right 545 } else { 546 labelMargin.right = this.theme.label.normalMargin.right 547 } 548 } 549 return labelMargin 550 } 551 552 private getLocalizedLabelMargin(): LocalizedMargin { 553 let localizedLabelMargin: LocalizedMargin = { start: LengthMetrics.vp(0), end: LengthMetrics.vp(0) } 554 if (this.label?.localizedLabelMargin?.start?.value !== void (0) && 555 this.lengthMetricsToVp(this.label.localizedLabelMargin.start) >= 0) { 556 localizedLabelMargin.start = this.label?.localizedLabelMargin?.start 557 } else if ((this.prefixSymbol?.normal || this.prefixSymbol?.activated) || this.prefixIcon?.src) { 558 if (this.isChipSizeEnum() && this.chipSize == ChipSize.SMALL) { 559 localizedLabelMargin.start = this.theme.label.localizedSmallMargin.start 560 } else { 561 localizedLabelMargin.start = this.theme.label.localizedNormalMargin.start 562 } 563 } 564 if (this.label?.localizedLabelMargin?.end?.value !== void (0) && 565 this.lengthMetricsToVp(this.label.localizedLabelMargin.end) >= 0) { 566 localizedLabelMargin.end = this.label?.localizedLabelMargin?.end 567 } else if ((this.suffixSymbol?.normal || this.suffixSymbol?.activated) || 568 this.suffixIcon?.src || this.useDefaultSuffixIcon) { 569 if (this.isChipSizeEnum() && this.chipSize == ChipSize.SMALL) { 570 localizedLabelMargin.end = this.theme.label.localizedSmallMargin.end 571 } else { 572 localizedLabelMargin.end = this.theme.label.localizedNormalMargin.end 573 } 574 } 575 return localizedLabelMargin 576 } 577 578 private getLabelStartEndVp(): LocalizedMargin { 579 let labelMargin: LocalizedMargin = this.getLocalizedLabelMargin() 580 if (this.label && (this.label.labelMargin !== void (0)) && (this.label.localizedLabelMargin === void (0))) { 581 let margin: Margin = this.getLabelMargin() 582 return { 583 start: LengthMetrics.vp(this.toVp(margin.left)), 584 end: LengthMetrics.vp(this.toVp(margin.right)) 585 } 586 } 587 return { 588 start: LengthMetrics.vp(this.lengthMetricsToVp(labelMargin.start)), 589 end: LengthMetrics.vp(this.lengthMetricsToVp(labelMargin.end)) 590 } 591 } 592 593 private getActualLabelMargin(): Margin | LocalizedMargin { 594 let localizedLabelMargin: LocalizedMargin = this.getLocalizedLabelMargin() 595 if (this.label && this.label.localizedLabelMargin !== void (0)) { 596 return localizedLabelMargin 597 } 598 if (this.label && this.label.labelMargin !== void (0)) { 599 return this.getLabelMargin() 600 } 601 return localizedLabelMargin 602 } 603 604 private getSuffixIconSize(): SizeOptions { 605 let suffixIconSize: SizeOptions = { width: 0, height: 0 } 606 if (this.suffixIcon?.size?.width !== void (0) && this.toVp(this.suffixIcon?.size?.width) >= 0) { 607 suffixIconSize.width = this.suffixIcon?.size?.width 608 } else { 609 if (this.getSuffixIconSrc()) { 610 suffixIconSize.width = this.theme.suffixIcon.size.width 611 } else { 612 suffixIconSize.width = 0 613 } 614 } 615 if (this.suffixIcon?.size?.height !== void (0) && this.toVp(this.suffixIcon?.size?.height) >= 0) { 616 suffixIconSize.height = this.suffixIcon?.size?.height 617 } else { 618 if (this.getSuffixIconSrc()) { 619 suffixIconSize.height = this.theme.suffixIcon.size.height 620 } else { 621 suffixIconSize.height = 0 622 } 623 } 624 return suffixIconSize 625 } 626 627 private getPrefixIconSize(): SizeOptions { 628 let prefixIconSize: SizeOptions = { width: 0, height: 0 } 629 if (this.prefixIcon?.size?.width !== void (0) && this.toVp(this.prefixIcon?.size?.width) >= 0) { 630 prefixIconSize.width = this.prefixIcon?.size?.width 631 } else { 632 if (this.prefixIcon?.src) { 633 prefixIconSize.width = this.theme.prefixIcon.size.width 634 } else { 635 prefixIconSize.width = 0 636 } 637 } 638 if (this.prefixIcon?.size?.height !== void (0) && this.toVp(this.prefixIcon?.size?.height) >= 0) { 639 prefixIconSize.height = this.prefixIcon?.size?.height 640 } else { 641 if (this.prefixIcon?.src) { 642 prefixIconSize.height = this.theme.prefixIcon.size.height 643 } else { 644 prefixIconSize.height = 0 645 } 646 } 647 return prefixIconSize 648 } 649 650 private getPrefixIconFilledColor(): ResourceColor { 651 if (this.getChipActive()) { 652 return this.prefixIcon?.activatedFillColor ?? this.theme.prefixIcon.activatedFillColor 653 } 654 return this.prefixIcon?.fillColor ?? this.theme.prefixIcon.fillColor 655 } 656 657 private getSuffixIconFilledColor(): ResourceColor { 658 if (this.getChipActive()) { 659 return this.suffixIcon?.activatedFillColor ?? this.theme.suffixIcon.activatedFillColor 660 } 661 return this.suffixIcon?.fillColor ?? this.theme.suffixIcon.fillColor 662 } 663 664 private getDefaultSymbolColor(): Array<ResourceColor> { 665 if (this.getChipActive()) { 666 return this.theme.defaultSymbol.activatedFontColor 667 } 668 return this.theme.defaultSymbol.normalFontColor 669 } 670 671 private getPrefixSymbolModifier(): SymbolGlyphModifier | undefined { 672 if (this.getChipActive()) { 673 return this.prefixSymbol?.activated 674 } 675 return this.prefixSymbol?.normal 676 } 677 678 private getSuffixSymbolModifier(): SymbolGlyphModifier | undefined { 679 if (this.getChipActive()) { 680 return this.suffixSymbol?.activated 681 } 682 return this.suffixSymbol?.normal 683 } 684 685 private getSuffixIconFocusable(): boolean { 686 return (this.useDefaultSuffixIcon && (this.allowClose ?? true)) || this.suffixIcon?.action !== void (0) 687 } 688 689 private getChipNodePadding(): LocalizedPadding { 690 return (this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL) ? this.theme.chipNode.localizedSmallPadding : 691 this.theme.chipNode.localizedNormalPadding 692 } 693 694 private getChipNodeRadius(): Dimension { 695 if (this.chipNodeRadius !== void (0) && this.toVp(this.chipNodeRadius) >= 0) { 696 return this.chipNodeRadius as Dimension 697 } else { 698 return ((this.isChipSizeEnum() && this.chipSize === ChipSize.SMALL) ? 699 this.theme.chipNode.smallBorderRadius : this.theme.chipNode.normalBorderRadius) 700 } 701 } 702 703 private getChipNodeBackGroundColor(): ResourceColor { 704 let currentColor: ResourceColor; 705 706 if (this.getChipActive()) { 707 currentColor = this.chipNodeActivatedBackgroundColor ?? this.theme.chipNode.activatedBackgroundColor 708 } else { 709 currentColor = this.chipNodeBackgroundColor ?? this.theme.chipNode.backgroundColor 710 } 711 712 let sourceColor: ColorMetrics; 713 714 try { 715 sourceColor = ColorMetrics.resourceColor(currentColor); 716 } catch (err) { 717 hilog.error(0x3900, 'Ace', `Chip resourceColor, error: ${err.toString()}`); 718 sourceColor = ColorMetrics.resourceColor(Color.Transparent); 719 } 720 if (!this.isShowPressedBackGroundColor) { 721 return sourceColor.color 722 } 723 724 return sourceColor 725 .blendColor(ColorMetrics.resourceColor("#19000000")) 726 .color 727 } 728 729 private getChipNodeHeight(): Length { 730 if (this.isChipSizeEnum()) { 731 return this.chipSize === ChipSize.SMALL ? this.theme.chipNode.smallHeight : this.theme.chipNode.normalHeight 732 } else { 733 this.chipNodeSize = this.chipSize as SizeOptions 734 return (this.chipNodeSize?.height !== void (0) && this.toVp(this.chipNodeSize?.height) >= 0) ? 735 this.toVp(this.chipNodeSize?.height) : this.theme.chipNode.normalHeight 736 } 737 } 738 739 private getLabelWidth(): number { 740 return px2vp(measure.measureText({ 741 textContent: this.label?.text ?? "", 742 fontSize: this.getLabelFontSize(), 743 fontFamily: this.label?.fontFamily ?? this.theme.label.fontFamily, 744 fontWeight: this.getLabelFontWeight(), 745 maxLines: 1, 746 overflow: TextOverflow.Ellipsis, 747 textAlign: TextAlign.Center 748 })) 749 } 750 751 private getCalculateChipNodeWidth(): number { 752 let calWidth: number = 0 753 let startEndVp: LocalizedMargin = this.getLabelStartEndVp() 754 calWidth += this.getChipNodePadding().start?.value ?? 0 755 calWidth += this.toVp(this.getPrefixChipWidth()) 756 calWidth += this.toVp(startEndVp.start?.value ?? 0) 757 calWidth += this.getLabelWidth() 758 calWidth += this.toVp(startEndVp.end?.value ?? 0) 759 calWidth += this.toVp(this.getSuffixChipWidth()) 760 calWidth += this.getChipNodePadding().end?.value ?? 0 761 return calWidth 762 } 763 764 private getPrefixChipWidth(): Length | undefined { 765 if (this.prefixSymbol?.normal || this.prefixSymbol?.activated) { 766 return this.prefixSymbolWidth 767 } else if (this.prefixIcon?.src) { 768 return this.getPrefixIconSize().width 769 } else { 770 return 0 771 } 772 } 773 774 private getSuffixChipWidth(): Length | undefined { 775 if (this.suffixSymbol?.normal || this.suffixSymbol?.activated) { 776 return this.suffixSymbolWidth 777 } else if (this.suffixIcon?.src) { 778 return this.getSuffixIconSize().width 779 } else if (!this.suffixIcon?.src && (this.allowClose ?? true)) { 780 return this.allowCloseSymbolWidth 781 } else { 782 return 0 783 } 784 } 785 786 private getReserveChipNodeWidth(): number { 787 return this.getCalculateChipNodeWidth() - this.getLabelWidth() + (this.theme.chipNode.minLabelWidth as number) 788 } 789 790 private getChipEnable(): boolean { 791 return this.chipEnabled || this.chipEnabled === void (0) 792 } 793 794 private getChipActive(): boolean { 795 if (typeof this.chipActivated === 'undefined') { 796 return false 797 } 798 return this.chipActivated 799 } 800 801 private getChipNodeOpacity(): number { 802 return this.chipOpacity 803 } 804 805 private handleTouch(event: TouchEvent) { 806 if (!this.getChipEnable()) { 807 return 808 } 809 if (this.isHover) { 810 if (event.type === TouchType.Down || event.type === TouchType.Move) { 811 this.isShowPressedBackGroundColor = true 812 } else if (event.type === TouchType.Up) { 813 this.isShowPressedBackGroundColor = false 814 } else { 815 this.isShowPressedBackGroundColor = false 816 } 817 } else { 818 if (event.type === TouchType.Down || event.type === TouchType.Move) { 819 this.isShowPressedBackGroundColor = true 820 } else if (event.type === TouchType.Up) { 821 this.isShowPressedBackGroundColor = false 822 } else { 823 this.isShowPressedBackGroundColor = false 824 } 825 } 826 } 827 828 private hoverAnimate(isHover: boolean) { 829 if (!this.getChipEnable()) { 830 return 831 } 832 this.isHover = isHover 833 if (this.isHover) { 834 this.isShowPressedBackGroundColor = true 835 } else { 836 this.isShowPressedBackGroundColor = false 837 } 838 } 839 840 private deleteChipNodeAnimate() { 841 animateTo({ duration: 150, curve: Curve.Sharp }, () => { 842 this.chipOpacity = 0 843 this.chipBlendColor = Color.Transparent 844 }) 845 animateTo({ 846 duration: 150, curve: Curve.FastOutLinearIn, onFinish: () => { 847 this.deleteChip = true 848 } 849 }, 850 () => { 851 this.chipScale = { x: 0.85, y: 0.85 } 852 }) 853 } 854 855 private getSuffixIconSrc(): ResourceStr | undefined { 856 this.useDefaultSuffixIcon = !this.suffixIcon?.src && (this.allowClose ?? true) 857 return this.useDefaultSuffixIcon ? this.theme.suffixIcon.defaultDeleteIcon : (this.suffixIcon?.src ?? void (0)) 858 } 859 860 private getChipNodeWidth(): Length { 861 if (!this.isChipSizeEnum()) { 862 this.chipNodeSize = this.chipSize as SizeOptions 863 if (this.chipNodeSize?.width !== void (0) && this.toVp(this.chipNodeSize.width) >= 0) { 864 return this.toVp(this.chipNodeSize.width) 865 } 866 } 867 let constraintWidth: ConstraintSizeOptions = this.getChipConstraintWidth() 868 return Math.min(Math.max(this.getCalculateChipNodeWidth(), 869 constraintWidth.minWidth as number), constraintWidth.maxWidth as number); 870 } 871 872 private getFocusOverlaySize(): SizeOptions { 873 return { 874 width: Math.max(this.getChipNodeWidth() as number, this.getChipConstraintWidth().minWidth as number) + 8, 875 height: this.getChipNodeHeight() as number + 8 876 } 877 } 878 879 private getChipConstraintWidth(): ConstraintSizeOptions { 880 let calcMinWidth: number = this.getReserveChipNodeWidth() 881 882 let constraintWidth: number = this.getCalculateChipNodeWidth() 883 let constraintSize: ConstraintSizeOptions 884 switch (this.chipBreakPoints) { 885 case BreakPointsType.SM: 886 constraintSize = { 887 minWidth: calcMinWidth, 888 maxWidth: Math.min(constraintWidth, this.theme.chipNode.breakPointConstraintWidth.breakPointSmMaxWidth) 889 } 890 break 891 case BreakPointsType.MD: 892 constraintSize = { 893 minWidth: Math.max(constraintWidth, this.theme.chipNode.breakPointConstraintWidth.breakPointMinWidth), 894 maxWidth: Math.min(constraintWidth, this.theme.chipNode.breakPointConstraintWidth.breakPointMdMaxWidth) 895 } 896 break 897 case BreakPointsType.LG: 898 constraintSize = { 899 minWidth: Math.max(constraintWidth, this.theme.chipNode.breakPointConstraintWidth.breakPointMinWidth), 900 maxWidth: Math.min(constraintWidth, this.theme.chipNode.breakPointConstraintWidth.breakPointLgMaxWidth) 901 } 902 break 903 default: 904 constraintSize = { minWidth: calcMinWidth, maxWidth: constraintWidth } 905 break 906 } 907 constraintSize.minWidth = Math.min(Math.max(this.getCalculateChipNodeWidth(), 908 constraintSize.minWidth as number), constraintSize.maxWidth as number) 909 constraintSize.minHeight = this.getChipNodeHeight() 910 if (!this.isChipSizeEnum() && this.chipNodeSize?.height !== void (0) && this.toVp(this.chipNodeSize?.height) >= 0) { 911 constraintSize.maxHeight = this.toVp(this.chipNodeSize.height) 912 constraintSize.minHeight = this.toVp(this.chipNodeSize.height) 913 } 914 if (!this.isChipSizeEnum() && this.chipNodeSize?.width !== void (0) && this.toVp(this.chipNodeSize?.width) >= 0) { 915 constraintSize.minWidth = this.toVp(this.chipNodeSize.width) 916 constraintSize.maxWidth = this.toVp(this.chipNodeSize.width) 917 } else if (this.toVp(this.fontSizeScale) >= this.theme.chipNode.suitAgeScale) { 918 constraintSize.minWidth = void (0) 919 constraintSize.maxWidth = void (0) 920 } 921 return constraintSize 922 } 923 924 @Builder 925 focusOverlay() { 926 Stack() { 927 if (this.chipNodeOnFocus && !this.suffixIconOnFocus) { 928 Stack() 929 .direction(this.chipDirection) 930 .borderRadius(this.toVp(this.getChipNodeRadius()) + 4) 931 .size(this.getFocusOverlaySize()) 932 .borderColor(this.theme.chipNode.focusOutlineColor) 933 .borderWidth(this.theme.chipNode.borderWidth) 934 } 935 } 936 .direction(this.chipDirection) 937 .size({ width: 1, height: 1 }) 938 .align(Alignment.Center) 939 } 940 941 @Styles 942 suffixIconFocusStyles() { 943 .borderColor(this.theme.chipNode.focusOutlineColor) 944 .borderWidth(this.getSuffixIconFocusable() ? this.theme.chipNode.borderWidth : 0) 945 } 946 947 @Styles 948 suffixIconNormalStyles() { 949 .borderColor(Color.Transparent) 950 .borderWidth(0) 951 } 952 953 aboutToAppear() { 954 let uiContent: UIContext = this.getUIContext(); 955 this.fontSizeScale = (uiContent.getHostContext() as common.UIAbilityContext)?.config?.fontSizeScale ?? 1; 956 this.smListener.on("change", (mediaQueryResult: mediaquery.MediaQueryResult) => { 957 if (mediaQueryResult.matches) { 958 this.chipBreakPoints = BreakPointsType.SM 959 } 960 }) 961 this.mdListener.on("change", (mediaQueryResult: mediaquery.MediaQueryResult) => { 962 if (mediaQueryResult.matches) { 963 this.chipBreakPoints = BreakPointsType.MD 964 } 965 }) 966 this.lgListener.on("change", (mediaQueryResult: mediaquery.MediaQueryResult) => { 967 if (mediaQueryResult.matches) { 968 this.chipBreakPoints = BreakPointsType.LG 969 } 970 }) 971 this.callbackId = this.getUIContext() 972 .getHostContext() 973 ?.getApplicationContext() 974 ?.on('environment', this.callbacks); 975 } 976 977 private getVisibility(): Visibility { 978 if (this.toVp(this.getChipNodeHeight()) > 0) { 979 return Visibility.Visible 980 } else { 981 return Visibility.None 982 } 983 } 984 985 aboutToDisappear() { 986 this.smListener.off("change") 987 this.mdListener.off("change") 988 this.lgListener.off("change") 989 if (this.callbackId) { 990 this.getUIContext() 991 .getHostContext() 992 ?.getApplicationContext() 993 ?.off('environment', this.callbackId); 994 this.callbackId = void (0) 995 } 996 } 997 998 @Builder 999 chipBuilder() { 1000 Button() { 1001 Row() { 1002 if (this.prefixSymbol?.normal || this.prefixSymbol?.activated) { 1003 SymbolGlyph() 1004 .fontSize(this.theme.defaultSymbol.fontSize) 1005 .fontColor(this.getDefaultSymbolColor()) 1006 .attributeModifier(this.getPrefixSymbolModifier()) 1007 .effectStrategy(SymbolEffectStrategy.NONE) 1008 .symbolEffect(this.symbolEffect, false) 1009 .symbolEffect(this.symbolEffect, this.theme.defaultSymbol.defaultEffect) 1010 .onSizeChange((oldValue, newValue) => { 1011 this.prefixSymbolWidth = newValue?.width 1012 }) 1013 .key('PrefixSymbolGlyph') 1014 } else if (this.prefixIcon?.src !== "") { 1015 Image(this.prefixIcon?.src) 1016 .direction(this.chipDirection) 1017 .opacity(this.getChipNodeOpacity()) 1018 .size(this.getPrefixIconSize()) 1019 .fillColor(this.getPrefixIconFilledColor()) 1020 .enabled(this.getChipEnable()) 1021 .objectFit(ImageFit.Cover) 1022 .focusable(false) 1023 .flexShrink(0) 1024 .visibility(this.getVisibility()) 1025 .draggable(false) 1026 } 1027 1028 Text(this.label?.text ?? "") 1029 .direction(this.chipDirection) 1030 .opacity(this.getChipNodeOpacity()) 1031 .fontSize(this.getLabelFontSize()) 1032 .fontColor(this.getLabelFontColor()) 1033 .fontFamily(this.getLabelFontFamily()) 1034 .fontWeight(this.getLabelFontWeight()) 1035 .margin(this.getActualLabelMargin()) 1036 .enabled(this.getChipEnable()) 1037 .maxLines(1) 1038 .textOverflow({ overflow: TextOverflow.Ellipsis }) 1039 .flexShrink(1) 1040 .focusable(true) 1041 .textAlign(TextAlign.Center) 1042 .visibility(this.getVisibility()) 1043 .draggable(false) 1044 1045 if (this.suffixSymbol?.normal || this.suffixSymbol?.activated) { 1046 Button({ type: ButtonType.Normal }) { 1047 SymbolGlyph() 1048 .fontSize(this.theme.defaultSymbol.fontSize) 1049 .fontColor(this.getDefaultSymbolColor()) 1050 .attributeModifier(this.getSuffixSymbolModifier()) 1051 .effectStrategy(SymbolEffectStrategy.NONE) 1052 .symbolEffect(this.symbolEffect, false) 1053 .symbolEffect(this.symbolEffect, this.theme.defaultSymbol.defaultEffect) 1054 .onSizeChange((oldValue, newValue) => { 1055 this.suffixSymbolWidth = newValue?.width 1056 }) 1057 .key('SuffixSymbolGlyph') 1058 } 1059 .onClick(this.getSuffixSymbolAction()) 1060 .accessibilityText(this.getSuffixSymbolAccessibilityText()) 1061 .accessibilityDescription(this.getSuffixSymbolAccessibilityDescription()) 1062 .accessibilityLevel(this.getSuffixSymbolAccessibilityLevel()) 1063 .backgroundColor(Color.Transparent) 1064 .borderRadius(0) 1065 .padding(0) 1066 .stateEffect(false) 1067 } else if (this.suffixIcon?.src !== "") { 1068 Button({ type: ButtonType.Normal }) { 1069 Image(this.getSuffixIconSrc()) 1070 .direction(this.chipDirection) 1071 .opacity(this.getChipNodeOpacity()) 1072 .size(this.getSuffixIconSize()) 1073 .fillColor(this.getSuffixIconFilledColor()) 1074 .enabled(this.getChipEnable()) 1075 .objectFit(ImageFit.Cover) 1076 .flexShrink(0) 1077 .visibility(this.getVisibility()) 1078 .draggable(false) 1079 .onFocus(() => { 1080 this.suffixIconOnFocus = true 1081 }) 1082 .onBlur(() => { 1083 this.suffixIconOnFocus = false 1084 }) 1085 } 1086 .backgroundColor(Color.Transparent) 1087 .borderRadius(0) 1088 .padding(0) 1089 .size(this.getSuffixIconSize()) 1090 .accessibilityText(this.getSuffixIconAccessibilityText()) 1091 .accessibilityDescription(this.getSuffixIconAccessibilityDescription()) 1092 .accessibilityLevel(this.getSuffixIconAccessibilityLevel()) 1093 .onClick(() => { 1094 if (!this.getChipEnable()) { 1095 return 1096 } 1097 if (this.suffixIcon?.action) { 1098 this.suffixIcon.action() 1099 return 1100 } 1101 if ((this.allowClose ?? true) && this.useDefaultSuffixIcon) { 1102 this.onClose() 1103 this.deleteChipNodeAnimate() 1104 return 1105 } 1106 this.onClicked() 1107 }) 1108 .focusable(this.getSuffixIconFocusable()) 1109 } else if (this.allowClose ?? true) { 1110 Button({ type: ButtonType.Normal }) { 1111 SymbolGlyph($r('sys.symbol.xmark')) 1112 .fontSize(this.theme.defaultSymbol.fontSize) 1113 .fontColor(this.getDefaultSymbolColor()) 1114 .onSizeChange((oldValue, newValue) => { 1115 this.allowCloseSymbolWidth = newValue?.width 1116 }) 1117 .key('AllowCloseSymbolGlyph') 1118 } 1119 .backgroundColor(Color.Transparent) 1120 .borderRadius(0) 1121 .padding(0) 1122 .accessibilityText(this.getCloseIconAccessibilityText()) 1123 .accessibilityDescription(this.getCloseIconAccessibilityDescription()) 1124 .accessibilityLevel(this.getCloseIconAccessibilityLevel()) 1125 .onClick(() => { 1126 if (!this.getChipEnable()) { 1127 return 1128 } 1129 this.onClose() 1130 this.deleteChipNodeAnimate() 1131 }) 1132 } 1133 1134 } 1135 .direction(this.chipDirection) 1136 .alignItems(VerticalAlign.Center) 1137 .justifyContent(FlexAlign.Center) 1138 .padding(this.getChipNodePadding()) 1139 .constraintSize(this.getChipConstraintWidth()) 1140 } 1141 .constraintSize(this.getChipConstraintWidth()) 1142 .direction(this.chipDirection) 1143 .type(ButtonType.Normal) 1144 .clip(false) 1145 .backgroundColor(this.getChipNodeBackGroundColor()) 1146 .borderRadius(this.getChipNodeRadius()) 1147 .enabled(this.getChipEnable()) 1148 .scale(this.chipScale) 1149 .focusable(true) 1150 .opacity(this.getChipNodeOpacity()) 1151 .padding(0) 1152 .accessibilityGroup(true) 1153 .accessibilityDescription(this.getAccessibilityDescription()) 1154 .accessibilityLevel(this.getAccessibilityLevel()) 1155 .accessibilityChecked(this.getAccessibilityChecked()) 1156 .accessibilitySelected(this.getAccessibilitySelected()) 1157 .onFocus(() => { 1158 this.chipNodeOnFocus = true 1159 }) 1160 .onBlur(() => { 1161 this.chipNodeOnFocus = false 1162 }) 1163 .onTouch((event) => { 1164 this.handleTouch(event) 1165 }) 1166 .onHover((isHover: boolean) => { 1167 if (isHover) { 1168 this.isShowPressedBackGroundColor = true 1169 } else { 1170 if (!this.isShowPressedBackGroundColor && isHover) { 1171 this.isShowPressedBackGroundColor = true 1172 } else { 1173 this.isShowPressedBackGroundColor = false 1174 } 1175 } 1176 }) 1177 .onKeyEvent((event) => { 1178 if (event.type === KeyType.Down && event.keyCode === KeyCode.KEYCODE_FORWARD_DEL && !this.suffixIconOnFocus) { 1179 this.deleteChipNodeAnimate() 1180 } 1181 }) 1182 .onClick(this.onClicked === noop ? undefined : this.onClicked.bind(this)) 1183 } 1184 1185 getSuffixSymbolAccessibilityLevel(): string { 1186 if (this.getChipActive()) { 1187 if (this.suffixSymbolOptions?.activatedAccessibility?.accessibilityLevel === 'no' || 1188 this.suffixSymbolOptions?.activatedAccessibility?.accessibilityLevel === 'no-hide-descendants') { 1189 return this.suffixSymbolOptions.activatedAccessibility.accessibilityLevel; 1190 } 1191 return this.suffixSymbolOptions?.action ? 'yes' : 'no'; 1192 } 1193 if (this.suffixSymbolOptions?.normalAccessibility?.accessibilityLevel === 'no' || 1194 this.suffixSymbolOptions?.normalAccessibility?.accessibilityLevel === 'no-hide-descendants') { 1195 return this.suffixSymbolOptions.normalAccessibility.accessibilityLevel; 1196 } 1197 return this.suffixSymbolOptions?.action ? 'yes' : 'no'; 1198 } 1199 1200 getSuffixSymbolAccessibilityDescription(): Resource | undefined { 1201 if (this.getChipActive()) { 1202 if (typeof this.suffixSymbolOptions?.activatedAccessibility?.accessibilityDescription !== 'undefined') { 1203 return this.suffixSymbolOptions.activatedAccessibility.accessibilityDescription as Resource; 1204 } 1205 return undefined; 1206 } 1207 if (typeof this.suffixSymbolOptions?.normalAccessibility?.accessibilityDescription !== 'undefined') { 1208 return this.suffixSymbolOptions.normalAccessibility.accessibilityDescription as Resource; 1209 } 1210 return undefined; 1211 } 1212 1213 getSuffixSymbolAccessibilityText(): Resource | undefined { 1214 if (this.getChipActive()) { 1215 if (typeof this.suffixSymbolOptions?.activatedAccessibility?.accessibilityText !== 'undefined') { 1216 return this.suffixSymbolOptions.activatedAccessibility.accessibilityText as Resource; 1217 } 1218 return undefined; 1219 } 1220 if (typeof this.suffixSymbolOptions?.normalAccessibility?.accessibilityText !== 'undefined') { 1221 return this.suffixSymbolOptions.normalAccessibility.accessibilityText as Resource; 1222 } 1223 return undefined; 1224 } 1225 1226 getSuffixSymbolAction(): Callback<ClickEvent> | undefined { 1227 if (typeof this.suffixSymbolOptions?.action === 'undefined') { 1228 return undefined; 1229 } 1230 return () => { 1231 if (!this.getChipEnable()) { 1232 return; 1233 } 1234 this.suffixSymbolOptions?.action?.(); 1235 }; 1236 } 1237 1238 private getAccessibilitySelected(): boolean | undefined { 1239 if (this.getChipAccessibilitySelectedType() === AccessibilitySelectedType.SELECTED) { 1240 return this.getChipActive(); 1241 } 1242 return undefined; 1243 } 1244 1245 private getAccessibilityChecked(): boolean | undefined { 1246 if (this.getChipAccessibilitySelectedType() === AccessibilitySelectedType.CHECKED) { 1247 return this.getChipActive(); 1248 } 1249 return undefined; 1250 } 1251 1252 private getChipAccessibilitySelectedType(): AccessibilitySelectedType { 1253 if (typeof this.chipActivated === 'undefined') { 1254 return AccessibilitySelectedType.CLICKED; 1255 } 1256 return this.chipAccessibilitySelectedType ?? AccessibilitySelectedType.CHECKED; 1257 } 1258 1259 private getCloseIconAccessibilityLevel(): string { 1260 if (this.closeOptions?.accessibilityLevel === 'no' || this.closeOptions?.accessibilityLevel === 'no-hide-descendants') { 1261 return this.closeOptions.accessibilityLevel; 1262 } 1263 return 'yes'; 1264 } 1265 1266 private getCloseIconAccessibilityDescription(): Resource | undefined { 1267 if (typeof this.closeOptions?.accessibilityDescription === 'undefined') { 1268 return undefined; 1269 } 1270 return this.closeOptions.accessibilityDescription as Resource; 1271 } 1272 1273 private getCloseIconAccessibilityText(): Resource { 1274 if (typeof this.closeOptions?.accessibilityText === 'undefined') { 1275 return $r('sys.string.delete_used_for_accessibility_text') 1276 } 1277 return this.closeOptions.accessibilityText as ESObject as Resource; 1278 } 1279 1280 private getSuffixIconAccessibilityLevel(): string { 1281 if (this.suffixIcon?.accessibilityLevel === 'no' || this.suffixIcon?.accessibilityLevel === 'no-hide-descendants') { 1282 return this.suffixIcon.accessibilityLevel; 1283 } 1284 return this.suffixIcon?.action ? 'yes' : 'no'; 1285 } 1286 1287 private getSuffixIconAccessibilityDescription(): Resource | undefined { 1288 if (typeof this.suffixIcon?.accessibilityDescription === 'undefined') { 1289 return undefined; 1290 } 1291 return this.suffixIcon.accessibilityDescription as ESObject as Resource; 1292 } 1293 1294 private getSuffixIconAccessibilityText(): Resource | undefined { 1295 if (typeof this.suffixIcon?.accessibilityText === 'undefined') { 1296 return undefined; 1297 } 1298 1299 return this.suffixIcon.accessibilityText as ESObject as Resource; 1300 } 1301 1302 private getAccessibilityLevel(): string | undefined { 1303 return this.chipAccessibilityLevel; 1304 } 1305 1306 private getAccessibilityDescription(): Resource | undefined { 1307 if (typeof this.chipAccessibilityDescription === 'undefined') { 1308 return undefined; 1309 } 1310 return this.chipAccessibilityDescription as ESObject as Resource; 1311 } 1312 1313 build() { 1314 if (!this.deleteChip) { 1315 this.chipBuilder() 1316 } 1317 } 1318} 1319