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