import * as React from 'react' import {__, _x} from '@wordpress/i18n' import cx from 'classnames' import { useState, createContext, } from '@wordpress/element' import { BaseControl, } from '@wordpress/components' import { Button, ButtonGroup, ButtonGroupOption, ButtonGroupRadioProps, } from '@ska/components' import EditableButton from './EditableButton' import RadioButton from './RadioButton' import { parseVariantValue, } from '../../../tailwind/classNames' import { buildOptions, } from './util' import { wrapArbitraryValue, type TailwindFeatureConfig, type TailwindFeature, } from '../..' import './style.scss' const noop = () => {} export interface RadioContextType { /** Display value instead of label on radio buttons. */ showValues: boolean /** Display "deselect" button instead of "remove" button next to a custom value */ deselectable: boolean /** Resolved or fallen back to defaults supports. */ supports: TailwindFeature['supports'] } export const RadioContext = createContext({ showValues: false, deselectable: false, supports: { variants: false, important: false, signed: false, arbitrary: true, variable: true, name: false, bare: false, }, }) export interface RadioProps extends Omit { /** What is this radio handling. */ type?: /** Handles selecting a variant (e.g. `md`, `lg`, `hover`). */ | 'variants' /** Handles selecting an option (e.g. `px`, `16`, `[12px]`). */ | 'options' /** What Tailwind features are supported. */ supports?: TailwindFeatureConfig['supports'] /** Non-conforming options will be converted to `ButtonGroupOption`. */ options: ButtonGroupOption[] | string[] | Map /** Can be used to determine if a radio button should be displayed as active. */ isActive?: (value: string) => boolean /** Action to perform when double clicking a radio button. */ onDoubleClick?: (doubleClickedValue: string) => void /** Add custom options. */ onAdd?: (addedValue: string) => void /** Edit custom options. */ onUpdate?: (nextValue: string, prevValue: string) => void /** Remove custom options. */ onRemove?: (removedValue: string) => void /** List of option values that are custom (and should render `` when applicable). */ arbitraryValues?: string[] /** Custom function to toggle important. */ toggleImportant?: () => string /** Custom function to toggle sign. */ toggleSigned?: () => string } interface SubComponents { Optimistic: typeof OptimisticRadio Tabs: typeof RadioTabs } /** * Radio buttons specialized for manipulating Tailwind utilities. */ const Radio: React.FC & SubComponents = props => { const { type = 'options', supports: providedSupports = {}, options, toggleImportant, toggleSigned, value: currentValue = '', onChange = noop, onAdd, isSmall = false, } = props const { variants = false, important = false, signed = false, arbitrary = false, variable = false, name = false, bare = false, } = providedSupports const supports = { variants, important, signed, arbitrary, variable, name, bare, } const OPTIONS = buildOptions(options) const { isImportant, isSigned, toggleImportant: defaultToggleImportant, toggleSigned: defaultToggleSigned, } = parseVariantValue(currentValue) const [showValues, setShowValues] = useState(false) const prepend = type === 'options' && <>