xref: /aosp_15_r20/external/perfetto/ui/src/widgets/chip.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2024 The Android Open Source Project
2//
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 m from 'mithril';
16import {classNames} from '../base/classnames';
17import {HTMLAttrs, Intent, classForIntent} from './common';
18import {Icon} from './icon';
19import {Spinner} from './spinner';
20
21interface CommonAttrs extends HTMLAttrs {
22  // Use minimal padding, reducing the overall size of the chip by a few px.
23  // Defaults to false.
24  compact?: boolean;
25  // Optional right icon.
26  rightIcon?: string;
27  // List of space separated class names forwarded to the icon.
28  className?: string;
29  // Show loading spinner instead of icon.
30  // Defaults to false.
31  loading?: boolean;
32  // Whether to use a filled icon
33  // Defaults to false;
34  iconFilled?: boolean;
35  // Indicate chip colouring by intent.
36  // Defaults to undefined aka "None"
37  intent?: Intent;
38  // Turns the chip into a pill shape.
39  rounded?: boolean;
40}
41
42interface IconChipAttrs extends CommonAttrs {
43  // Icon chips require an icon.
44  icon: string;
45}
46
47interface LabelChipAttrs extends CommonAttrs {
48  // Label chips require a label.
49  label: string;
50  // Label chips can have an optional icon.
51  icon?: string;
52}
53
54export type ChipAttrs = LabelChipAttrs | IconChipAttrs;
55
56export class Chip implements m.ClassComponent<ChipAttrs> {
57  view({attrs}: m.CVnode<ChipAttrs>) {
58    const {
59      icon,
60      compact,
61      rightIcon,
62      className,
63      iconFilled,
64      intent = Intent.None,
65      rounded,
66      ...htmlAttrs
67    } = attrs;
68
69    const label = 'label' in attrs ? attrs.label : undefined;
70
71    const classes = classNames(
72      compact && 'pf-compact',
73      classForIntent(intent),
74      icon && !label && 'pf-icon-only',
75      className,
76      rounded && 'pf-rounded',
77    );
78
79    return m(
80      '.pf-chip',
81      {
82        ...htmlAttrs,
83        className: classes,
84      },
85      this.renderIcon(attrs),
86      rightIcon &&
87        m(Icon, {
88          className: 'pf-right-icon',
89          icon: rightIcon,
90          filled: iconFilled,
91        }),
92      label || '\u200B', // Zero width space keeps chip in-flow
93    );
94  }
95
96  private renderIcon(attrs: ChipAttrs): m.Children {
97    const {icon, iconFilled} = attrs;
98    const className = 'pf-left-icon';
99    if (attrs.loading) {
100      return m(Spinner, {className});
101    } else if (icon) {
102      return m(Icon, {className, icon, filled: iconFilled});
103    } else {
104      return undefined;
105    }
106  }
107}
108
109/**
110 * Space chips out with a little gap between each one.
111 */
112export class ChipBar implements m.ClassComponent<HTMLAttrs> {
113  view({attrs, children}: m.CVnode<HTMLAttrs>): m.Children {
114    return m('.pf-chip-bar', attrs, children);
115  }
116}
117