blob: cd71d3fc80e7b693794bda703f7c85cbeaa6f052 [file] [log] [blame]
Steve Goltona50d0be2024-09-25 13:27:15 +00001// 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}