1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2023 The Android Open Source Project 2*6dbdd20aSAndroid Build Coastguard Worker// 3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*6dbdd20aSAndroid Build Coastguard Worker// 7*6dbdd20aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*6dbdd20aSAndroid Build Coastguard Worker// 9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License. 14*6dbdd20aSAndroid Build Coastguard Worker 15*6dbdd20aSAndroid Build Coastguard Workerimport m from 'mithril'; 16*6dbdd20aSAndroid Build Coastguard Workerimport {classNames} from '../base/classnames'; 17*6dbdd20aSAndroid Build Coastguard Workerimport {HTMLAttrs, HTMLButtonAttrs, Intent, classForIntent} from './common'; 18*6dbdd20aSAndroid Build Coastguard Workerimport {Icon} from './icon'; 19*6dbdd20aSAndroid Build Coastguard Workerimport {Popup} from './popup'; 20*6dbdd20aSAndroid Build Coastguard Workerimport {Spinner} from './spinner'; 21*6dbdd20aSAndroid Build Coastguard Worker 22*6dbdd20aSAndroid Build Coastguard Workerinterface CommonAttrs extends HTMLButtonAttrs { 23*6dbdd20aSAndroid Build Coastguard Worker // Always show the button as if the "active" pseudo class were applied, which 24*6dbdd20aSAndroid Build Coastguard Worker // makes the button look permanently pressed. 25*6dbdd20aSAndroid Build Coastguard Worker // Useful for when the button represents some toggleable state, such as 26*6dbdd20aSAndroid Build Coastguard Worker // showing/hiding a popup menu. 27*6dbdd20aSAndroid Build Coastguard Worker // Defaults to false. 28*6dbdd20aSAndroid Build Coastguard Worker active?: boolean; 29*6dbdd20aSAndroid Build Coastguard Worker // Use minimal padding, reducing the overall size of the button by a few px. 30*6dbdd20aSAndroid Build Coastguard Worker // Defaults to false. 31*6dbdd20aSAndroid Build Coastguard Worker compact?: boolean; 32*6dbdd20aSAndroid Build Coastguard Worker // Optional right icon. 33*6dbdd20aSAndroid Build Coastguard Worker rightIcon?: string; 34*6dbdd20aSAndroid Build Coastguard Worker // List of space separated class names forwarded to the icon. 35*6dbdd20aSAndroid Build Coastguard Worker className?: string; 36*6dbdd20aSAndroid Build Coastguard Worker // Allow clicking this button to close parent popups. 37*6dbdd20aSAndroid Build Coastguard Worker // Defaults to false. 38*6dbdd20aSAndroid Build Coastguard Worker dismissPopup?: boolean; 39*6dbdd20aSAndroid Build Coastguard Worker // Show loading spinner instead of icon. 40*6dbdd20aSAndroid Build Coastguard Worker // Defaults to false. 41*6dbdd20aSAndroid Build Coastguard Worker loading?: boolean; 42*6dbdd20aSAndroid Build Coastguard Worker // Whether to use a filled icon 43*6dbdd20aSAndroid Build Coastguard Worker // Defaults to false; 44*6dbdd20aSAndroid Build Coastguard Worker iconFilled?: boolean; 45*6dbdd20aSAndroid Build Coastguard Worker // Indicate button colouring by intent. 46*6dbdd20aSAndroid Build Coastguard Worker // Defaults to undefined aka "None" 47*6dbdd20aSAndroid Build Coastguard Worker intent?: Intent; 48*6dbdd20aSAndroid Build Coastguard Worker} 49*6dbdd20aSAndroid Build Coastguard Worker 50*6dbdd20aSAndroid Build Coastguard Workerinterface IconButtonAttrs extends CommonAttrs { 51*6dbdd20aSAndroid Build Coastguard Worker // Icon buttons require an icon. 52*6dbdd20aSAndroid Build Coastguard Worker icon: string; 53*6dbdd20aSAndroid Build Coastguard Worker} 54*6dbdd20aSAndroid Build Coastguard Worker 55*6dbdd20aSAndroid Build Coastguard Workerinterface LabelButtonAttrs extends CommonAttrs { 56*6dbdd20aSAndroid Build Coastguard Worker // Label buttons require a label. 57*6dbdd20aSAndroid Build Coastguard Worker label: string; 58*6dbdd20aSAndroid Build Coastguard Worker // Label buttons can have an optional icon. 59*6dbdd20aSAndroid Build Coastguard Worker icon?: string; 60*6dbdd20aSAndroid Build Coastguard Worker} 61*6dbdd20aSAndroid Build Coastguard Worker 62*6dbdd20aSAndroid Build Coastguard Workerexport type ButtonAttrs = LabelButtonAttrs | IconButtonAttrs; 63*6dbdd20aSAndroid Build Coastguard Worker 64*6dbdd20aSAndroid Build Coastguard Workerexport class Button implements m.ClassComponent<ButtonAttrs> { 65*6dbdd20aSAndroid Build Coastguard Worker view({attrs}: m.CVnode<ButtonAttrs>) { 66*6dbdd20aSAndroid Build Coastguard Worker const { 67*6dbdd20aSAndroid Build Coastguard Worker icon, 68*6dbdd20aSAndroid Build Coastguard Worker active, 69*6dbdd20aSAndroid Build Coastguard Worker compact, 70*6dbdd20aSAndroid Build Coastguard Worker rightIcon, 71*6dbdd20aSAndroid Build Coastguard Worker className, 72*6dbdd20aSAndroid Build Coastguard Worker dismissPopup, 73*6dbdd20aSAndroid Build Coastguard Worker iconFilled, 74*6dbdd20aSAndroid Build Coastguard Worker intent = Intent.None, 75*6dbdd20aSAndroid Build Coastguard Worker ...htmlAttrs 76*6dbdd20aSAndroid Build Coastguard Worker } = attrs; 77*6dbdd20aSAndroid Build Coastguard Worker 78*6dbdd20aSAndroid Build Coastguard Worker const label = 'label' in attrs ? attrs.label : undefined; 79*6dbdd20aSAndroid Build Coastguard Worker 80*6dbdd20aSAndroid Build Coastguard Worker const classes = classNames( 81*6dbdd20aSAndroid Build Coastguard Worker active && 'pf-active', 82*6dbdd20aSAndroid Build Coastguard Worker compact && 'pf-compact', 83*6dbdd20aSAndroid Build Coastguard Worker classForIntent(intent), 84*6dbdd20aSAndroid Build Coastguard Worker icon && !label && 'pf-icon-only', 85*6dbdd20aSAndroid Build Coastguard Worker dismissPopup && Popup.DISMISS_POPUP_GROUP_CLASS, 86*6dbdd20aSAndroid Build Coastguard Worker className, 87*6dbdd20aSAndroid Build Coastguard Worker ); 88*6dbdd20aSAndroid Build Coastguard Worker 89*6dbdd20aSAndroid Build Coastguard Worker return m( 90*6dbdd20aSAndroid Build Coastguard Worker 'button.pf-button', 91*6dbdd20aSAndroid Build Coastguard Worker { 92*6dbdd20aSAndroid Build Coastguard Worker ...htmlAttrs, 93*6dbdd20aSAndroid Build Coastguard Worker className: classes, 94*6dbdd20aSAndroid Build Coastguard Worker }, 95*6dbdd20aSAndroid Build Coastguard Worker this.renderIcon(attrs), 96*6dbdd20aSAndroid Build Coastguard Worker rightIcon && 97*6dbdd20aSAndroid Build Coastguard Worker m(Icon, { 98*6dbdd20aSAndroid Build Coastguard Worker className: 'pf-right-icon', 99*6dbdd20aSAndroid Build Coastguard Worker icon: rightIcon, 100*6dbdd20aSAndroid Build Coastguard Worker filled: iconFilled, 101*6dbdd20aSAndroid Build Coastguard Worker }), 102*6dbdd20aSAndroid Build Coastguard Worker label || '\u200B', // Zero width space keeps button in-flow 103*6dbdd20aSAndroid Build Coastguard Worker ); 104*6dbdd20aSAndroid Build Coastguard Worker } 105*6dbdd20aSAndroid Build Coastguard Worker 106*6dbdd20aSAndroid Build Coastguard Worker private renderIcon(attrs: ButtonAttrs): m.Children { 107*6dbdd20aSAndroid Build Coastguard Worker const {icon, iconFilled} = attrs; 108*6dbdd20aSAndroid Build Coastguard Worker const className = 'pf-left-icon'; 109*6dbdd20aSAndroid Build Coastguard Worker if (attrs.loading) { 110*6dbdd20aSAndroid Build Coastguard Worker return m(Spinner, {className}); 111*6dbdd20aSAndroid Build Coastguard Worker } else if (icon) { 112*6dbdd20aSAndroid Build Coastguard Worker return m(Icon, {className, icon, filled: iconFilled}); 113*6dbdd20aSAndroid Build Coastguard Worker } else { 114*6dbdd20aSAndroid Build Coastguard Worker return undefined; 115*6dbdd20aSAndroid Build Coastguard Worker } 116*6dbdd20aSAndroid Build Coastguard Worker } 117*6dbdd20aSAndroid Build Coastguard Worker} 118*6dbdd20aSAndroid Build Coastguard Worker 119*6dbdd20aSAndroid Build Coastguard Worker/** 120*6dbdd20aSAndroid Build Coastguard Worker * Space buttons out with a little gap between each one. 121*6dbdd20aSAndroid Build Coastguard Worker */ 122*6dbdd20aSAndroid Build Coastguard Workerexport class ButtonBar implements m.ClassComponent<HTMLAttrs> { 123*6dbdd20aSAndroid Build Coastguard Worker view({attrs, children}: m.CVnode<HTMLAttrs>): m.Children { 124*6dbdd20aSAndroid Build Coastguard Worker return m('.pf-button-bar', attrs, children); 125*6dbdd20aSAndroid Build Coastguard Worker } 126*6dbdd20aSAndroid Build Coastguard Worker} 127