/* * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. * * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. */ /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import classNames from 'classnames'; import React, { FunctionComponent, HTMLAttributes, ReactNode } from 'react'; import { OuiScreenReaderOnly } from '../../accessibility'; import { OuiButtonGroupButton } from './button_group_button'; import { colorToClassNameMap, ButtonColor } from '../button'; import { OuiButtonContentProps } from '../button_content'; import { CommonProps } from '../../common'; import { htmlIdGenerator } from '../../../services'; export interface OuiButtonGroupOptionProps extends OuiButtonContentProps, CommonProps { /** * Each option must have a unique `id` for maintaining selection */ id: string; /** * Each option must have a `label` even for icons which will be applied as the `aria-label` */ label: ReactNode; isDisabled?: boolean; /** * The value of the radio input. */ value?: any; /** * The type of the underlying HTML button */ type?: 'button' | 'submit' | 'reset'; } export type OuiButtonGroupProps = CommonProps & { /** * Typical sizing is `s`. Medium `m` size should be reserved for major features. * `compressed` is meant to be used alongside and within compressed forms. */ buttonSize?: 's' | 'm' | 'compressed'; isDisabled?: boolean; /** * Expands the whole group to the full width of the container. * Each button gets equal widths no matter the content */ isFullWidth?: boolean; /** * Hides the label to only show the `iconType` provided by the `option` */ isIconOnly?: boolean; /** * A hidden group title (required for accessibility) */ legend: string; /** * Compressed styles don't support `ghost` color (Color will be changed to "text") */ color?: ButtonColor; /** * Actual type is `'single' | 'multi'`. * Determines how the selection of the group should be handled. * With `'single'` only one option can be selected at a time (similar to radio group). * With `'multi'` multiple options selected (similar to checkbox group). */ type?: 'single' | 'multi'; /** * An array of #OuiButtonGroupOptionProps */ options: OuiButtonGroupOptionProps[]; } & ( | { /** * Default for `type` is single so it can also be excluded */ type?: 'single'; /** * The `name` attribute for radio inputs; * Defaults to a random string */ name?: string; /** * Styles the selected option to look selected (usually with `fill`) * Required by and only used in `type='single'`. */ idSelected: string; /** * Single: Returns the `id` of the clicked option and the `value` */ onChange: (id: string, value?: any) => void; idToSelectedMap?: never; } | { type: 'multi'; /** * A map of `id`s as keys with the selected boolean values. * Required by and only used in `type='multi'`. */ idToSelectedMap?: { [id: string]: boolean }; /** * Multi: Returns the `id` of the clicked option */ onChange: (id: string) => void; idSelected?: never; name?: never; } ); type Props = Omit, 'onChange' | 'color'> & OuiButtonGroupProps; const groupSizeToClassNameMap = { s: '--small', m: '--medium', compressed: '--compressed', }; export const OuiButtonGroup: FunctionComponent = ({ className, buttonSize = 's', color = 'text', idSelected = '', idToSelectedMap = {}, isDisabled = false, isFullWidth = false, isIconOnly = false, legend, name, onChange, options = [], type = 'single', ...rest }) => { // Compressed style can't support `ghost` color because it's more like a form field than a button const badColorCombo = buttonSize === 'compressed' && color === 'ghost'; const resolvedColor = badColorCombo ? 'text' : color; if (badColorCombo) { console.warn( 'OuiButtonGroup of compressed size does not support the ghost color. It will render as text instead.' ); } const classes = classNames( 'ouiButtonGroup', `ouiButtonGroup${groupSizeToClassNameMap[buttonSize]}`, `ouiButtonGroup${colorToClassNameMap[resolvedColor]}`, { 'ouiButtonGroup--fullWidth': isFullWidth, 'ouiButtonGroup--isDisabled': isDisabled, }, className ); const typeIsSingle = type === 'single'; const nameIfSingle = name || htmlIdGenerator()(); return (
{legend}
{options.map((option, index) => { return ( ); })}
); };