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 */
15import { SymbolGlyphModifier } from '@ohos.arkui.modifier';
16import {
17  AccessibilitySelectedType,
18  Chip,
19  ChipSize,
20  ChipSuffixSymbolGlyphOptions,
21  ChipSymbolGlyphOptions,
22  CloseOptions,
23  PrefixIconOptions,
24  SuffixIconOptions
25} from '@ohos.arkui.advanced.Chip';
26
27interface ChipGroupTheme {
28  itemStyle: ChipGroupStyleTheme;
29  chipGroupSpace: ChipGroupSpaceOptions;
30  chipGroupPadding: ChipGroupPaddingOptions
31}
32
33const noop = (selectedIndexes: Array<number>) => {
34}
35const colorStops: ([string, number])[] = [['rgba(0, 0, 0, 1)', 0], ['rgba(0, 0, 0, 0)', 1]]
36const defaultTheme: ChipGroupTheme = {
37  itemStyle: {
38    size: ChipSize.NORMAL,
39    backgroundColor: $r('sys.color.ohos_id_color_button_normal'),
40    fontColor: $r('sys.color.ohos_id_color_text_primary'),
41    selectedFontColor: $r('sys.color.ohos_id_color_text_primary_contrary'),
42    selectedBackgroundColor: $r('sys.color.ohos_id_color_emphasize'),
43    fillColor: $r('sys.color.ohos_id_color_secondary'),
44    selectedFillColor: $r('sys.color.ohos_id_color_text_primary_contrary'),
45  },
46  chipGroupSpace: { itemSpace: 8, startSpace: 16, endSpace: 16 },
47  chipGroupPadding: { top: 14, bottom: 14 }
48}
49
50const iconGroupSuffixTheme: IconGroupSuffixTheme = {
51  backgroundColor: $r('sys.color.ohos_id_color_button_normal'),
52  borderRadius: $r('sys.float.ohos_id_corner_radius_tips_instant_tip'),
53  smallIconSize: 16,
54  normalIconSize: 24,
55  smallBackgroundSize: 28,
56  normalBackgroundSize: 36,
57  marginLeft: 8,
58  marginRight: 16,
59  fillColor: $r('sys.color.ohos_id_color_primary'),
60  defaultEffect: -1
61}
62
63enum ChipGroupHeight {
64  NORMAL = 36,
65  SMALL = 28,
66}
67
68interface IconOptions {
69  src: ResourceStr;
70  size?: SizeOptions;
71}
72
73interface ChipGroupPaddingOptions {
74  top: Length;
75  bottom: Length;
76}
77
78interface ChipGroupStyleTheme {
79  size: ChipSize | SizeOptions;
80  backgroundColor: ResourceColor;
81  fontColor: ResourceColor;
82  selectedFontColor: ResourceColor;
83  selectedBackgroundColor: ResourceColor;
84  fillColor: ResourceColor;
85  selectedFillColor: ResourceColor;
86}
87
88interface LabelOptions {
89  text: string;
90}
91
92export interface SuffixImageIconOptions extends IconOptions {
93  action?: VoidCallback;
94  accessibilityText?: ResourceStr;
95  accessibilityDescription?: ResourceStr;
96  accessibilityLevel?: string;
97}
98
99export interface ChipGroupItemOptions {
100  prefixIcon?: IconOptions;
101  prefixSymbol?: ChipSymbolGlyphOptions;
102  label: LabelOptions;
103  suffixIcon?: IconOptions;
104  suffixImageIcon?: SuffixImageIconOptions;
105  suffixSymbol?: ChipSymbolGlyphOptions;
106  suffixSymbolOptions?: ChipSuffixSymbolGlyphOptions;
107  allowClose?: boolean;
108  closeOptions?: CloseOptions;
109  accessibilityDescription?: ResourceStr;
110  accessibilityLevel?: string;
111}
112
113export interface ChipItemStyle {
114  size?: ChipSize | SizeOptions;
115  backgroundColor?: ResourceColor;
116  fontColor?: ResourceColor;
117  selectedFontColor?: ResourceColor;
118  selectedBackgroundColor?: ResourceColor;
119}
120
121interface ChipGroupSpaceOptions {
122  itemSpace?: number | string;
123  startSpace?: Length;
124  endSpace?: Length;
125}
126
127export interface IconItemOptions {
128  icon: IconOptions;
129  action: Callback<void>;
130  accessibilityText?: ResourceStr;
131  accessibilityDescription?: ResourceStr;
132  accessibilityLevel?: string;
133}
134
135export interface SymbolItemOptions {
136  symbol: SymbolGlyphModifier;
137  action: VoidCallback;
138  accessibilityText?: ResourceStr;
139  accessibilityDescription?: ResourceStr;
140  accessibilityLevel?: string;
141}
142
143interface IconGroupSuffixTheme {
144  smallIconSize: number;
145  normalIconSize: number;
146  backgroundColor: ResourceColor;
147  smallBackgroundSize: number;
148  normalBackgroundSize: number;
149  borderRadius: Dimension;
150  marginLeft: number;
151  marginRight: number;
152  fillColor: ResourceColor;
153  defaultEffect: number;
154}
155
156function parseDimension<T>(
157  uiContext: UIContext,
158  value: Dimension | Length | undefined,
159  isValid: Callback<string, boolean>,
160  defaultValue: T
161): T {
162  if (value === void (0) || value === null) {
163    return defaultValue;
164  }
165  const resourceManager = uiContext.getHostContext()?.resourceManager;
166  if (!resourceManager) {
167    return defaultValue;
168  }
169  if (typeof value === 'object') {
170    let temp: Resource = value as Resource;
171    if (temp.type === 10002 || temp.type === 10007) {
172      if (resourceManager.getNumber(temp.id) >= 0) {
173        return value as T;
174      }
175    } else if (temp.type === 10003) {
176      if (isValidDimensionString(resourceManager.getStringSync(temp.id))) {
177        return value as T;
178      }
179    }
180  } else if (typeof value === 'number') {
181    if (value >= 0) {
182      return value as T;
183    }
184  } else if (typeof value === 'string') {
185    if (isValid(value)) {
186      return value as T;
187    }
188  }
189  return defaultValue;
190}
191
192function isValidString(dimension: string, regex: RegExp): boolean {
193  const matches = dimension.match(regex);
194  if (!matches || matches.length < 3) {
195    return false;
196  }
197  const value = Number.parseFloat(matches[1]);
198  return value >= 0;
199}
200
201function isValidDimensionString(dimension: string): boolean {
202  return isValidString(dimension, new RegExp('(-?\\d+(?:\\.\\d+)?)_?(fp|vp|px|lpx|%)?$', 'i'));
203}
204
205function isValidDimensionNoPercentageString(dimension: string): boolean {
206  return isValidString(dimension, new RegExp('(-?\\d+(?:\\.\\d+)?)_?(fp|vp|px|lpx)?$', 'i'));
207}
208
209@Component
210export struct IconGroupSuffix {
211  @Consume chipSize: ChipSize | SizeOptions;
212  @Prop items: Array<IconItemOptions | SymbolGlyphModifier | SymbolItemOptions> = [];
213  symbolEffect: SymbolEffect = new SymbolEffect();
214
215  private getBackgroundSize(): number {
216    if (this.chipSize === ChipSize.SMALL) {
217      return iconGroupSuffixTheme.smallBackgroundSize;
218    } else {
219      return iconGroupSuffixTheme.normalBackgroundSize;
220    }
221  }
222
223  private getIconSize(val?: Length): Length {
224    if (val === undefined) {
225      return this.chipSize === ChipSize.SMALL ?
226      iconGroupSuffixTheme.smallIconSize :
227      iconGroupSuffixTheme.normalIconSize;
228    }
229    let value: Length;
230    if (this.chipSize === ChipSize.SMALL) {
231      value = parseDimension(this.getUIContext(), val, isValidDimensionString, iconGroupSuffixTheme.smallIconSize);
232    } else {
233      value = parseDimension(this.getUIContext(), val, isValidDimensionString, iconGroupSuffixTheme.normalIconSize);
234    }
235    return value;
236  }
237
238  @Builder
239  SymbolItemBuilder(item: SymbolItemOptions) {
240    SymbolGlyph()
241      .fontColor([iconGroupSuffixTheme.fillColor])
242      .fontSize(this.getIconSize())
243      .attributeModifier(item.symbol)
244      .focusable(true)
245      .effectStrategy(SymbolEffectStrategy.NONE)
246      .symbolEffect(this.symbolEffect, false)
247      .symbolEffect(this.symbolEffect, iconGroupSuffixTheme.defaultEffect)
248  }
249
250  @Builder
251  IconItemBuilder(item: IconItemOptions) {
252    Image(item.icon.src)
253      .fillColor(iconGroupSuffixTheme.fillColor)
254      .size({
255        width: this.getIconSize(item.icon.size?.width),
256        height: this.getIconSize(item.icon.size?.height)
257      })
258      .focusable(true)
259  }
260
261  build() {
262    Row({ space: 8 }) {
263      ForEach(this.items || [], (suffixItem: IconItemOptions | SymbolGlyphModifier | SymbolItemOptions) => {
264        Button() {
265          if (suffixItem instanceof SymbolGlyphModifier) {
266            SymbolGlyph()
267              .fontColor([iconGroupSuffixTheme.fillColor])
268              .fontSize(this.getIconSize())
269              .attributeModifier(suffixItem)
270              .focusable(true)
271              .effectStrategy(SymbolEffectStrategy.NONE)
272              .symbolEffect(this.symbolEffect, false)
273              .symbolEffect(this.symbolEffect, iconGroupSuffixTheme.defaultEffect)
274          } else if (this.isSymbolItem(suffixItem)) {
275            this.SymbolItemBuilder(suffixItem as SymbolItemOptions)
276          } else {
277            this.IconItemBuilder(suffixItem as IconItemOptions)
278          }
279        }
280        .size({
281          width: this.getBackgroundSize(),
282          height: this.getBackgroundSize()
283        })
284        .backgroundColor(iconGroupSuffixTheme.backgroundColor)
285        .borderRadius(iconGroupSuffixTheme.borderRadius)
286        .accessibilityText(this.getAccessibilityText(suffixItem))
287        .accessibilityDescription(this.getAccessibilityDescription(suffixItem))
288        .accessibilityLevel(this.getAccessibilityLevel(suffixItem))
289        .onClick(() => {
290          if (!(suffixItem instanceof SymbolGlyphModifier)) {
291            suffixItem.action();
292          }
293        })
294        .borderRadius(iconGroupSuffixTheme.borderRadius)
295      })
296    }
297  }
298
299  private isSymbolItem(item: IconItemOptions | SymbolItemOptions): boolean {
300    return typeof (item as SymbolItemOptions).symbol !== 'undefined';
301  }
302
303  private getAccessibilityLevel(item: IconItemOptions | SymbolGlyphModifier | SymbolItemOptions): string {
304    if (item instanceof SymbolGlyphModifier) {
305      return 'auto';
306    }
307    return item.accessibilityLevel ?? 'auto';
308  }
309
310  private getAccessibilityDescription(
311    item: IconItemOptions | SymbolGlyphModifier | SymbolItemOptions
312  ): Resource | undefined {
313    if (item instanceof SymbolGlyphModifier || typeof item.accessibilityDescription === 'undefined') {
314      return undefined;
315    }
316    return item.accessibilityDescription as ESObject as Resource;
317  }
318
319  private getAccessibilityText(item: IconItemOptions | SymbolGlyphModifier | SymbolItemOptions): Resource | undefined {
320    if (item instanceof SymbolGlyphModifier || typeof item.accessibilityText === 'undefined') {
321      return undefined;
322    }
323    return item.accessibilityText as ESObject as Resource;
324  }
325}
326
327@Component
328export struct ChipGroup {
329  @Prop @Watch('onItemsChange') items: ChipGroupItemOptions[] = [];
330  @Prop @Watch('itemStyleOnChange') itemStyle: ChipItemStyle = defaultTheme.itemStyle;
331  @Provide chipSize: ChipSize | SizeOptions = defaultTheme.itemStyle.size;
332  @Prop selectedIndexes: Array<number> = [0];
333  @Prop @Watch('onMultipleChange') multiple: boolean = false;
334  @Prop chipGroupSpace: ChipGroupSpaceOptions = defaultTheme.chipGroupSpace;
335  @BuilderParam suffix?: Callback<void>;
336  public onChange: Callback<Array<number>> = noop;
337  private scroller: Scroller = new Scroller();
338  @State isReachEnd: boolean = this.scroller.isAtEnd();
339  @Prop chipGroupPadding: ChipGroupPaddingOptions = defaultTheme.chipGroupPadding;
340  @State isRefresh: boolean = true;
341
342  onItemsChange() {
343    this.isRefresh = !this.isRefresh;
344  }
345
346  onMultipleChange() {
347    this.selectedIndexes = this.getSelectedIndexes();
348  }
349
350  itemStyleOnChange() {
351    this.chipSize = this.getChipSize();
352  }
353
354  aboutToAppear() {
355    this.itemStyleOnChange();
356    if (this.getSelectedIndexes().length === 0) {
357      this.selectedIndexes = [0];
358    }
359  }
360
361  private getChipSize(): ChipSize | SizeOptions {
362    if (this.itemStyle && this.itemStyle.size) {
363      if (typeof this.itemStyle.size === 'object') {
364        if (!this.itemStyle.size.width || !this.itemStyle.size.height || !this.itemStyle.size) {
365          return defaultTheme.itemStyle.size;
366        }
367      }
368      return this.itemStyle.size;
369    }
370    return defaultTheme.itemStyle.size;
371  }
372
373  private getFontColor(): ResourceColor {
374    if (this.itemStyle && this.itemStyle.fontColor) {
375      if (typeof this.itemStyle.fontColor === 'object') {
376        let temp: Resource = this.itemStyle.fontColor as Resource;
377        if (temp == undefined || temp == null) {
378          return defaultTheme.itemStyle.fontColor;
379        }
380        if (temp.type === 10001) {
381          return this.itemStyle.fontColor;
382        }
383        return defaultTheme.itemStyle.fontColor;
384      }
385      return this.itemStyle.fontColor;
386    }
387    return defaultTheme.itemStyle.fontColor;
388  }
389
390  private getSelectedFontColor(): ResourceColor {
391    if (this.itemStyle && this.itemStyle.selectedFontColor) {
392      if (typeof this.itemStyle.selectedFontColor === 'object') {
393        let temp: Resource = this.itemStyle.selectedFontColor as Resource;
394        if (temp == undefined || temp == null) {
395          return defaultTheme.itemStyle.selectedFontColor;
396        }
397        if (temp.type === 10001) {
398          return this.itemStyle.selectedFontColor;
399        }
400        return defaultTheme.itemStyle.selectedFontColor;
401      }
402      return this.itemStyle.selectedFontColor;
403    }
404    return defaultTheme.itemStyle.selectedFontColor;
405  }
406
407  private getFillColor(): ResourceColor {
408    if (this.itemStyle && this.itemStyle.fontColor) {
409      return this.itemStyle.fontColor;
410    }
411    return defaultTheme.itemStyle.fillColor;
412  }
413
414  private getSelectedFillColor(): ResourceColor {
415    if (this.itemStyle && this.itemStyle.selectedFontColor) {
416      return this.itemStyle.selectedFontColor;
417    }
418    return defaultTheme.itemStyle.selectedFillColor;
419  }
420
421  private getBackgroundColor(): ResourceColor {
422    if (this.itemStyle && this.itemStyle.backgroundColor) {
423      if (typeof this.itemStyle.backgroundColor === 'object') {
424        let temp: Resource = this.itemStyle.backgroundColor as Resource;
425        if (temp == undefined || temp == null) {
426          return defaultTheme.itemStyle.backgroundColor;
427        }
428        if (temp.type === 10001) {
429          return this.itemStyle.backgroundColor;
430        }
431        return defaultTheme.itemStyle.backgroundColor;
432      }
433      return this.itemStyle.backgroundColor;
434    }
435    return defaultTheme.itemStyle.backgroundColor;
436  }
437
438  private getSelectedBackgroundColor(): ResourceColor {
439    if (this.itemStyle && this.itemStyle.selectedBackgroundColor) {
440      if (typeof this.itemStyle.selectedBackgroundColor === 'object') {
441        let temp: Resource = this.itemStyle.selectedBackgroundColor as Resource;
442        if (temp == undefined || temp == null) {
443          return defaultTheme.itemStyle.selectedBackgroundColor;
444        }
445        if (temp.type === 10001) {
446          return this.itemStyle.selectedBackgroundColor;
447        }
448        return defaultTheme.itemStyle.selectedBackgroundColor;
449      }
450      return this.itemStyle.selectedBackgroundColor;
451    }
452    return defaultTheme.itemStyle.selectedBackgroundColor;
453  }
454
455  private getSelectedIndexes(): Array<number> {
456    let temp: number[] = [];
457    temp = (this.selectedIndexes ?? [0]).filter(
458      (element, index, array) => {
459        return (
460          element >= 0 &&
461            element % 1 == 0 &&
462            element != null &&
463            element != undefined &&
464            array.indexOf(element) === index &&
465            element < (this.items || []).length);
466      });
467    return temp;
468  }
469
470  private isMultiple(): boolean {
471    return this.multiple ?? false;
472  }
473
474  private getChipGroupItemSpace() {
475    if (this.chipGroupSpace == undefined) {
476      return defaultTheme.chipGroupSpace.itemSpace
477    }
478    return parseDimension(
479      this.getUIContext(),
480      this.chipGroupSpace.itemSpace,
481      isValidDimensionNoPercentageString,
482      defaultTheme.chipGroupSpace.itemSpace
483    );
484  }
485
486  private getChipGroupStartSpace() {
487    if (this.chipGroupSpace == undefined) {
488      return defaultTheme.chipGroupSpace.startSpace
489    }
490    return parseDimension(
491      this.getUIContext(),
492      this.chipGroupSpace.startSpace,
493      isValidDimensionNoPercentageString,
494      defaultTheme.chipGroupSpace.startSpace
495    );
496  }
497
498  private getChipGroupEndSpace() {
499    if (this.chipGroupSpace == undefined) {
500      return defaultTheme.chipGroupSpace.endSpace
501    }
502    return parseDimension(
503      this.getUIContext(),
504      this.chipGroupSpace.endSpace,
505      isValidDimensionNoPercentageString,
506      defaultTheme.chipGroupSpace.endSpace
507    );
508  }
509
510  private getOnChange(): (selectedIndexes: Array<number>) => void {
511    return this.onChange ?? noop;
512  }
513
514  private isSelected(itemIndex: number): boolean {
515    if (!this.isMultiple()) {
516      return itemIndex == this.getSelectedIndexes()[0];
517    } else {
518      return this.getSelectedIndexes().some((element, index, array) => {
519        return (element == itemIndex);
520      })
521    }
522  }
523
524  private getPaddingTop() {
525    if (!this.chipGroupPadding || !this.chipGroupPadding.top) {
526      return defaultTheme.chipGroupPadding.top
527    }
528    return parseDimension(
529      this.getUIContext(),
530      this.chipGroupPadding.top,
531      isValidDimensionNoPercentageString,
532      defaultTheme.chipGroupPadding.top
533    );
534  }
535
536  private getPaddingBottom() {
537    if (!this.chipGroupPadding || !this.chipGroupPadding.bottom) {
538      return defaultTheme.chipGroupPadding.bottom
539    }
540    return parseDimension(
541      this.getUIContext(),
542      this.chipGroupPadding.bottom,
543      isValidDimensionNoPercentageString,
544      defaultTheme.chipGroupPadding.bottom
545    );
546  }
547
548  private getChipGroupHeight() {
549    if (typeof this.chipSize === 'string') {
550      if (this.chipSize === ChipSize.NORMAL) {
551        return ChipGroupHeight.NORMAL;
552      } else {
553        return ChipGroupHeight.SMALL;
554      }
555    } else if (typeof this.chipSize === 'object') {
556      return this.chipSize.height as number
557    } else {
558      return ChipGroupHeight.NORMAL
559    }
560  }
561
562  build() {
563    Row() {
564      Stack() {
565        Scroll(this.scroller) {
566          Row({ space: this.getChipGroupItemSpace() }) {
567            ForEach(this.items || [], (chipItem: ChipGroupItemOptions, index) => {
568              if (chipItem) {
569                Chip({
570                  prefixIcon: this.getPrefixIcon(chipItem),
571                  prefixSymbol: chipItem?.prefixSymbol,
572                  label: {
573                    text: chipItem?.label?.text ?? ' ',
574                    fontColor: this.getFontColor(),
575                    activatedFontColor: this.getSelectedFontColor(),
576                  },
577                  suffixIcon: this.getSuffixIcon(chipItem),
578                  suffixSymbol: chipItem?.suffixSymbol,
579                  suffixSymbolOptions: chipItem.suffixSymbolOptions,
580                  allowClose: chipItem.allowClose ?? false,
581                  closeOptions: chipItem.closeOptions,
582                  enabled: true,
583                  activated: this.isSelected(index),
584                  backgroundColor: this.getBackgroundColor(),
585                  size: this.getChipSize(),
586                  activatedBackgroundColor: this.getSelectedBackgroundColor(),
587                  accessibilitySelectedType:
588                  this.multiple ? AccessibilitySelectedType.CHECKED : AccessibilitySelectedType.SELECTED,
589                  accessibilityDescription: chipItem.accessibilityDescription,
590                  accessibilityLevel: chipItem.accessibilityLevel,
591                  onClicked: () => {
592                    if (this.isSelected(index)) {
593                      if (!(!this.isMultiple())) {
594                        if (this.getSelectedIndexes().length > 1) {
595                          this.selectedIndexes.splice(this.selectedIndexes.indexOf(index), 1);
596                        }
597                      }
598                    } else {
599                      if (!this.selectedIndexes || this.selectedIndexes.length === 0) {
600                        this.selectedIndexes = this.getSelectedIndexes();
601                      }
602                      if (!this.isMultiple()) {
603                        this.selectedIndexes = [];
604                      }
605                      this.selectedIndexes.push(index);
606                    }
607                    this.getOnChange()(this.getSelectedIndexes());
608                  }
609                })
610              }
611            }, () => {
612              return JSON.stringify(this.isRefresh);
613            });
614          }
615          .padding({
616            left: this.getChipGroupStartSpace(),
617            right: this.getChipGroupEndSpace()
618          })
619          .constraintSize({ minWidth: '100%' })
620        }
621        .scrollable(ScrollDirection.Horizontal)
622        .scrollBar(BarState.Off)
623        .align(Alignment.Start)
624        .width('100%')
625        .clip(false)
626        .onScroll(() => {
627          this.isReachEnd = this.scroller.isAtEnd();
628        })
629
630        if (this.suffix && !this.isReachEnd) {
631          Stack()
632            .width(iconGroupSuffixTheme.normalBackgroundSize)
633            .height(this.getChipGroupHeight())
634            .linearGradient({ angle: 90, colors: colorStops })
635            .blendMode(BlendMode.DST_IN, BlendApplyType.OFFSCREEN)
636            .hitTestBehavior(HitTestMode.None)
637        }
638      }
639      .padding({ top: this.getPaddingTop(), bottom: this.getPaddingBottom() })
640      .layoutWeight(1)
641      .blendMode(BlendMode.SRC_OVER, BlendApplyType.OFFSCREEN)
642      .alignContent(Alignment.End)
643
644      if (this.suffix) {
645        Row() {
646          this.suffix();
647        }.padding({
648          left: iconGroupSuffixTheme.marginLeft,
649          right: iconGroupSuffixTheme.marginRight
650        })
651      }
652    }
653    .align(Alignment.End)
654    .width('100%')
655  }
656
657  getPrefixIcon(chipItem: ChipGroupItemOptions): PrefixIconOptions {
658    return {
659      src: chipItem.prefixIcon?.src ?? '',
660      size: chipItem.prefixIcon?.size ?? undefined,
661      fillColor: this.getFillColor(),
662      activatedFillColor: this.getSelectedFillColor()
663    };
664  }
665
666  private getSuffixIcon(chipItem: ChipGroupItemOptions): SuffixIconOptions {
667    if (typeof chipItem.suffixImageIcon !== 'undefined') {
668      return {
669        src: chipItem.suffixImageIcon.src,
670        size: chipItem.suffixImageIcon.size,
671        fillColor: this.getFillColor(),
672        activatedFillColor: this.getSelectedFillColor(),
673        action: chipItem.suffixImageIcon.action,
674        accessibilityText: chipItem.suffixImageIcon.accessibilityText,
675        accessibilityDescription: chipItem.suffixImageIcon.accessibilityDescription,
676        accessibilityLevel: chipItem.suffixImageIcon.accessibilityLevel,
677      };
678    }
679    return {
680      src: chipItem.suffixIcon?.src ?? '',
681      size: chipItem.suffixIcon?.size ?? undefined,
682      fillColor: this.getFillColor(),
683      activatedFillColor: this.getSelectedFillColor()
684    };
685  }
686}
687