Add RadioGroup + Radio
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/canon': patch
|
||||
---
|
||||
|
||||
Add new `RadioGroup` + `Radio` component to Canon
|
||||
@@ -591,6 +591,96 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.canon-RadioGroup {
|
||||
color: var(--canon-fg-primary);
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-RadioGroup[data-orientation="horizontal"] .canon-RadioGroupContent {
|
||||
gap: var(--canon-space-4);
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.canon-RadioGroupContent {
|
||||
gap: var(--canon-space-2);
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-Radio {
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
font-size: var(--canon-font-size-2);
|
||||
color: var(--canon-fg-primary);
|
||||
forced-color-adjust: none;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
box-sizing: border-box;
|
||||
border: .125rem solid var(--canon-border);
|
||||
background: var(--canon-gray-1);
|
||||
border-radius: var(--canon-radius-full);
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
transition: all .2s;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-border);
|
||||
}
|
||||
|
||||
&[data-selected] {
|
||||
&:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
border-width: .25rem;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-focus-visible]:before {
|
||||
outline: 2px solid var(--canon-ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&[data-disabled] {
|
||||
cursor: not-allowed;
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-invalid]:before, &[data-invalid][data-selected]:before {
|
||||
border-color: var(--canon-border-danger);
|
||||
}
|
||||
|
||||
&[data-disabled][data-invalid] {
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.canon-TableRoot {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
.canon-RadioGroup {
|
||||
color: var(--canon-fg-primary);
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-RadioGroup[data-orientation="horizontal"] .canon-RadioGroupContent {
|
||||
gap: var(--canon-space-4);
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.canon-RadioGroupContent {
|
||||
gap: var(--canon-space-2);
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-Radio {
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
font-size: var(--canon-font-size-2);
|
||||
color: var(--canon-fg-primary);
|
||||
forced-color-adjust: none;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
box-sizing: border-box;
|
||||
border: .125rem solid var(--canon-border);
|
||||
background: var(--canon-gray-1);
|
||||
border-radius: var(--canon-radius-full);
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
transition: all .2s;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-border);
|
||||
}
|
||||
|
||||
&[data-selected] {
|
||||
&:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
border-width: .25rem;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-focus-visible]:before {
|
||||
outline: 2px solid var(--canon-ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&[data-disabled] {
|
||||
cursor: not-allowed;
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-invalid]:before, &[data-invalid][data-selected]:before {
|
||||
border-color: var(--canon-border-danger);
|
||||
}
|
||||
|
||||
&[data-disabled][data-invalid] {
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9815,6 +9815,96 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.canon-RadioGroup {
|
||||
color: var(--canon-fg-primary);
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-RadioGroup[data-orientation="horizontal"] .canon-RadioGroupContent {
|
||||
gap: var(--canon-space-4);
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.canon-RadioGroupContent {
|
||||
gap: var(--canon-space-2);
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canon-Radio {
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
font-size: var(--canon-font-size-2);
|
||||
color: var(--canon-fg-primary);
|
||||
forced-color-adjust: none;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
box-sizing: border-box;
|
||||
border: .125rem solid var(--canon-border);
|
||||
background: var(--canon-gray-1);
|
||||
border-radius: var(--canon-radius-full);
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
transition: all .2s;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-border);
|
||||
}
|
||||
|
||||
&[data-selected] {
|
||||
&:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
border-width: .25rem;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-focus-visible]:before {
|
||||
outline: 2px solid var(--canon-ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&[data-disabled] {
|
||||
cursor: not-allowed;
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-invalid]:before, &[data-invalid][data-selected]:before {
|
||||
border-color: var(--canon-border-danger);
|
||||
}
|
||||
|
||||
&[data-disabled][data-invalid] {
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.canon-TableRoot {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
|
||||
@@ -18,7 +18,10 @@ import { FocusEvent as FocusEvent_2 } from 'react';
|
||||
import { ForwardRefExoticComponent } from 'react';
|
||||
import { HTMLAttributes } from 'react';
|
||||
import { JSX as JSX_2 } from 'react/jsx-runtime';
|
||||
import { LinkProps as LinkProps_2 } from 'react-aria-components';
|
||||
import { Menu as Menu_2 } from '@base-ui-components/react/menu';
|
||||
import type { RadioGroupProps as RadioGroupProps_2 } from 'react-aria-components';
|
||||
import type { RadioProps as RadioProps_2 } from 'react-aria-components';
|
||||
import { ReactElement } from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
import { RefAttributes } from 'react';
|
||||
@@ -174,6 +177,28 @@ export interface ButtonIconProps extends ButtonProps_2 {
|
||||
| Partial<Record<Breakpoint_2, 'primary' | 'secondary'>>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export const ButtonLink: ForwardRefExoticComponent<
|
||||
ButtonLinkProps & RefAttributes<HTMLAnchorElement>
|
||||
>;
|
||||
|
||||
// @public
|
||||
export interface ButtonLinkProps extends LinkProps_2 {
|
||||
// (undocumented)
|
||||
children?: ReactNode;
|
||||
// (undocumented)
|
||||
iconEnd?: ReactElement;
|
||||
// (undocumented)
|
||||
iconStart?: ReactElement;
|
||||
// (undocumented)
|
||||
size?: 'small' | 'medium' | Partial<Record<Breakpoint_2, 'small' | 'medium'>>;
|
||||
// (undocumented)
|
||||
variant?:
|
||||
| 'primary'
|
||||
| 'secondary'
|
||||
| Partial<Record<Breakpoint_2, 'primary' | 'secondary'>>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface ButtonProps extends ButtonProps_2 {
|
||||
// (undocumented)
|
||||
@@ -1009,6 +1034,27 @@ export type PositionProps = GetPropDefTypes<typeof positionPropDefs>;
|
||||
// @public (undocumented)
|
||||
export type PropDef<T = any> = RegularPropDef<T> | ResponsivePropDef<T>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const Radio: ForwardRefExoticComponent<
|
||||
RadioProps & RefAttributes<HTMLLabelElement>
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const RadioGroup: ForwardRefExoticComponent<
|
||||
RadioGroupProps & RefAttributes<HTMLDivElement>
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface RadioGroupProps
|
||||
extends Omit<RadioGroupProps_2, 'children'>,
|
||||
Omit<FieldLabelProps, 'htmlFor' | 'id'> {
|
||||
// (undocumented)
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface RadioProps extends RadioProps_2 {}
|
||||
|
||||
// @public (undocumented)
|
||||
export type ReactNodePropDef = {
|
||||
type: 'ReactNode';
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed 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 type { Meta, StoryObj } from '@storybook/react';
|
||||
import { RadioGroup, Radio } from './RadioGroup';
|
||||
|
||||
const meta = {
|
||||
title: 'Forms/RadioGroup',
|
||||
component: RadioGroup,
|
||||
} satisfies Meta<typeof RadioGroup>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
label: 'What is your favorite pokemon?',
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const Horizontal: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
orientation: 'horizontal',
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const Disabled: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
isDisabled: true,
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const DisabledSingle: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander" isDisabled>
|
||||
Charmander
|
||||
</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const DisabledAndSelected: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
value: 'charmander',
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander" isDisabled>
|
||||
Charmander
|
||||
</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const Invalid: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
name: 'pokemon',
|
||||
isInvalid: true,
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander" isDisabled>
|
||||
Charmander
|
||||
</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const Validation: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
name: 'pokemon',
|
||||
defaultValue: 'charmander',
|
||||
validationBehavior: 'aria',
|
||||
validate: value => (value === 'charmander' ? 'Nice try!' : null),
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
|
||||
export const ReadOnly: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
isReadOnly: true,
|
||||
defaultValue: 'charmander',
|
||||
},
|
||||
render: args => (
|
||||
<RadioGroup {...args}>
|
||||
<Radio value="bulbasaur">Bulbasaur</Radio>
|
||||
<Radio value="charmander">Charmander</Radio>
|
||||
<Radio value="squirtle">Squirtle</Radio>
|
||||
</RadioGroup>
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
.canon-RadioGroup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: var(--canon-fg-primary);
|
||||
}
|
||||
|
||||
.canon-RadioGroup[data-orientation='horizontal'] .canon-RadioGroupContent {
|
||||
flex-direction: row;
|
||||
gap: var(--canon-space-4);
|
||||
}
|
||||
|
||||
.canon-RadioGroupContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--canon-space-2);
|
||||
}
|
||||
|
||||
.canon-Radio {
|
||||
display: flex;
|
||||
/* This is needed so the HiddenInput is positioned correctly */
|
||||
position: relative;
|
||||
align-items: center;
|
||||
gap: var(--canon-space-2);
|
||||
font-size: var(--canon-font-size-2);
|
||||
color: var(--canon-fg-primary);
|
||||
forced-color-adjust: none;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
box-sizing: border-box;
|
||||
border: 0.125rem solid var(--canon-border);
|
||||
background: var(--canon-gray-1);
|
||||
border-radius: var(--canon-radius-full);
|
||||
transition: all 200ms;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-border);
|
||||
}
|
||||
|
||||
&[data-selected] {
|
||||
&:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
border-width: 0.25rem;
|
||||
}
|
||||
|
||||
&[data-pressed]:before {
|
||||
border-color: var(--canon-bg-solid);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-focus-visible]:before {
|
||||
outline: 2px solid var(--canon-ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
&[data-disabled] {
|
||||
cursor: not-allowed;
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-invalid]:before {
|
||||
border-color: var(--canon-border-danger);
|
||||
}
|
||||
|
||||
&[data-invalid][data-selected]:before {
|
||||
border-color: var(--canon-border-danger);
|
||||
}
|
||||
|
||||
/* Ensure disabled state prevails over invalid state */
|
||||
&[data-disabled][data-invalid] {
|
||||
color: var(--canon-fg-disabled);
|
||||
|
||||
&:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
background: var(--canon-bg-disabled);
|
||||
}
|
||||
|
||||
&[data-selected]:before {
|
||||
border-color: var(--canon-border-disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed 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 { forwardRef, useEffect } from 'react';
|
||||
import {
|
||||
RadioGroup as AriaRadioGroup,
|
||||
Radio as AriaRadio,
|
||||
FieldError,
|
||||
} from 'react-aria-components';
|
||||
import clsx from 'clsx';
|
||||
import { FieldLabel } from '../FieldLabel';
|
||||
|
||||
import type { RadioGroupProps, RadioProps } from './types';
|
||||
|
||||
/** @public */
|
||||
export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
className,
|
||||
label,
|
||||
secondaryLabel,
|
||||
description,
|
||||
isRequired,
|
||||
'aria-label': ariaLabel,
|
||||
'aria-labelledby': ariaLabelledBy,
|
||||
children,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
useEffect(() => {
|
||||
if (!label && !ariaLabel && !ariaLabelledBy) {
|
||||
console.warn(
|
||||
'RadioGroup requires either a visible label, aria-label, or aria-labelledby for accessibility',
|
||||
);
|
||||
}
|
||||
}, [label, ariaLabel, ariaLabelledBy]);
|
||||
|
||||
// If a secondary label is provided, use it. Otherwise, use 'Required' if the field is required.
|
||||
const secondaryLabelText =
|
||||
secondaryLabel || (isRequired ? 'Required' : null);
|
||||
|
||||
return (
|
||||
<AriaRadioGroup
|
||||
className={clsx('canon-RadioGroup', className)}
|
||||
aria-label={ariaLabel}
|
||||
aria-labelledby={ariaLabelledBy}
|
||||
{...rest}
|
||||
ref={ref}
|
||||
>
|
||||
<FieldLabel
|
||||
label={label}
|
||||
secondaryLabel={secondaryLabelText}
|
||||
description={description}
|
||||
/>
|
||||
<div className="canon-RadioGroupContent">{children}</div>
|
||||
<FieldError className="canon-TextFieldError" />
|
||||
</AriaRadioGroup>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
RadioGroup.displayName = 'RadioGroup';
|
||||
|
||||
/** @public */
|
||||
export const Radio = forwardRef<HTMLLabelElement, RadioProps>((props, ref) => {
|
||||
const { className, ...rest } = props;
|
||||
|
||||
return (
|
||||
<AriaRadio className={clsx('canon-Radio', className)} {...rest} ref={ref} />
|
||||
);
|
||||
});
|
||||
|
||||
RadioGroup.displayName = 'RadioGroup';
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
export * from './RadioGroup';
|
||||
export * from './types';
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed 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 type {
|
||||
RadioGroupProps as AriaRadioGroupProps,
|
||||
RadioProps as AriaRadioProps,
|
||||
} from 'react-aria-components';
|
||||
import type { FieldLabelProps } from '../FieldLabel/types';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
/** @public */
|
||||
export interface RadioGroupProps
|
||||
extends Omit<AriaRadioGroupProps, 'children'>,
|
||||
Omit<FieldLabelProps, 'htmlFor' | 'id'> {
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface RadioProps extends AriaRadioProps {}
|
||||
@@ -30,6 +30,7 @@
|
||||
@import '../components/Icon/styles.css';
|
||||
@import '../components/Link/styles.css';
|
||||
@import '../components/Menu/Menu.styles.css';
|
||||
@import '../components/RadioGroup/RadioGroup.styles.css';
|
||||
@import '../components/Table/styles.css';
|
||||
@import '../components/Table/TableCell/TableCell.styles.css';
|
||||
@import '../components/Table/TableCellText/TableCellText.styles.css';
|
||||
|
||||
+12
-10
@@ -28,27 +28,29 @@ export * from './components/Box';
|
||||
export * from './components/Grid';
|
||||
export * from './components/Flex';
|
||||
export * from './components/Container';
|
||||
export * from './components/Text';
|
||||
export * from './components/Heading';
|
||||
|
||||
// UI components
|
||||
export * from './components/Avatar';
|
||||
export * from './components/Button';
|
||||
export * from './components/ButtonIcon';
|
||||
export * from './components/ButtonLink';
|
||||
export * from './components/Checkbox';
|
||||
export * from './components/Collapsible';
|
||||
export * from './components/DataTable';
|
||||
export * from './components/FieldLabel';
|
||||
export * from './components/Heading';
|
||||
export * from './components/Icon';
|
||||
export * from './components/ButtonIcon';
|
||||
export * from './components/Checkbox';
|
||||
export * from './components/Table';
|
||||
export * from './components/Tabs';
|
||||
export * from './components/TextField';
|
||||
export * from './components/Tooltip';
|
||||
export * from './components/Menu';
|
||||
export * from './components/ScrollArea';
|
||||
export * from './components/Link';
|
||||
export * from './components/Menu';
|
||||
export * from './components/RadioGroup';
|
||||
export * from './components/ScrollArea';
|
||||
export * from './components/Select';
|
||||
export * from './components/Switch';
|
||||
export * from './components/Table';
|
||||
export * from './components/Tabs';
|
||||
export * from './components/Text';
|
||||
export * from './components/TextField';
|
||||
export * from './components/Tooltip';
|
||||
|
||||
// Types
|
||||
export * from './types';
|
||||
|
||||
Reference in New Issue
Block a user