Merge pull request #30335 from backstage/canon-use-style
Canon - Bring styles into a single place
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/canon': patch
|
||||
---
|
||||
|
||||
We are transforming how we structure our class names and data attributes definitions for all components. They are now all set in the same place.
|
||||
@@ -245,6 +245,9 @@ export interface CheckboxProps {
|
||||
value?: string;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type ClassNamesMap = Record<string, string>;
|
||||
|
||||
// @public
|
||||
export const Collapsible: {
|
||||
Root: ForwardRefExoticComponent<
|
||||
@@ -267,6 +270,247 @@ export const Collapsible: {
|
||||
// @public (undocumented)
|
||||
export type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 'auto';
|
||||
|
||||
// @public
|
||||
export type ComponentClassNames<T extends ComponentDefinitionName> =
|
||||
(typeof componentDefinitions)[T]['classNames'];
|
||||
|
||||
// @public
|
||||
export interface ComponentDefinition {
|
||||
// (undocumented)
|
||||
classNames: ClassNamesMap;
|
||||
// (undocumented)
|
||||
dataAttributes?: DataAttributesMap;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type ComponentDefinitionName = keyof typeof componentDefinitions;
|
||||
|
||||
// @public
|
||||
export const componentDefinitions: {
|
||||
readonly Avatar: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-AvatarRoot';
|
||||
readonly image: 'canon-AvatarImage';
|
||||
readonly fallback: 'canon-AvatarFallback';
|
||||
};
|
||||
readonly dataAttributes: {
|
||||
readonly size: readonly ['small', 'medium', 'large'];
|
||||
};
|
||||
};
|
||||
readonly Box: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-Box';
|
||||
};
|
||||
};
|
||||
readonly Button: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-Button';
|
||||
};
|
||||
readonly dataAttributes: {
|
||||
readonly size: readonly ['small', 'medium', 'large'];
|
||||
readonly variant: readonly ['primary', 'secondary', 'ghost'];
|
||||
};
|
||||
};
|
||||
readonly ButtonIcon: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-ButtonIcon';
|
||||
};
|
||||
};
|
||||
readonly ButtonLink: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-ButtonLink';
|
||||
};
|
||||
};
|
||||
readonly Checkbox: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-CheckboxRoot';
|
||||
readonly label: 'canon-CheckboxLabel';
|
||||
readonly indicator: 'canon-CheckboxIndicator';
|
||||
};
|
||||
readonly dataAttributes: {
|
||||
readonly checked: readonly [true, false];
|
||||
};
|
||||
};
|
||||
readonly Collapsible: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-CollapsibleRoot';
|
||||
readonly trigger: 'canon-CollapsibleTrigger';
|
||||
readonly panel: 'canon-CollapsiblePanel';
|
||||
};
|
||||
};
|
||||
readonly Container: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-Container';
|
||||
};
|
||||
};
|
||||
readonly FieldLabel: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-FieldLabel';
|
||||
readonly label: 'canon-FieldLabelLabel';
|
||||
readonly secondaryLabel: 'canon-FieldLabelSecondaryLabel';
|
||||
readonly description: 'canon-FieldLabelDescription';
|
||||
};
|
||||
};
|
||||
readonly Flex: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-Flex';
|
||||
};
|
||||
};
|
||||
readonly Grid: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-Grid';
|
||||
readonly item: 'canon-GridItem';
|
||||
};
|
||||
};
|
||||
readonly Heading: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-Heading';
|
||||
};
|
||||
readonly dataAttributes: {
|
||||
readonly variant: readonly ['title1', 'title2', 'title3', 'subtitle'];
|
||||
readonly color: readonly ['primary', 'secondary', 'muted'];
|
||||
readonly truncate: readonly [true, false];
|
||||
};
|
||||
};
|
||||
readonly Icon: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-Icon';
|
||||
};
|
||||
};
|
||||
readonly Link: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-Link';
|
||||
};
|
||||
readonly dataAttributes: {
|
||||
readonly variant: readonly ['subtitle', 'body', 'caption', 'label'];
|
||||
readonly weight: readonly ['regular', 'bold'];
|
||||
};
|
||||
};
|
||||
readonly Menu: {
|
||||
readonly classNames: {
|
||||
readonly trigger: 'canon-MenuTrigger';
|
||||
readonly backdrop: 'canon-MenuBackdrop';
|
||||
readonly positioner: 'canon-MenuPositioner';
|
||||
readonly popup: 'canon-MenuPopup';
|
||||
readonly arrow: 'canon-MenuArrow';
|
||||
readonly item: 'canon-MenuItem';
|
||||
readonly group: 'canon-MenuGroup';
|
||||
readonly groupLabel: 'canon-MenuGroupLabel';
|
||||
readonly radioGroup: 'canon-MenuRadioGroup';
|
||||
readonly radioItem: 'canon-MenuRadioItem';
|
||||
readonly radioItemIndicator: 'canon-MenuRadioItemIndicator';
|
||||
readonly checkboxItem: 'canon-MenuCheckboxItem';
|
||||
readonly checkboxItemIndicator: 'canon-MenuCheckboxItemIndicator';
|
||||
readonly submenuTrigger: 'canon-MenuSubmenuTrigger';
|
||||
readonly separator: 'canon-MenuSeparator';
|
||||
};
|
||||
};
|
||||
readonly RadioGroup: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-RadioGroup';
|
||||
readonly content: 'canon-RadioGroupContent';
|
||||
readonly radio: 'canon-Radio';
|
||||
};
|
||||
};
|
||||
readonly ScrollArea: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-ScrollAreaRoot';
|
||||
readonly viewport: 'canon-ScrollAreaViewport';
|
||||
readonly scrollbar: 'canon-ScrollAreaScrollbar';
|
||||
readonly thumb: 'canon-ScrollAreaThumb';
|
||||
};
|
||||
};
|
||||
readonly Select: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-Select';
|
||||
readonly required: 'canon-SelectRequired';
|
||||
readonly trigger: 'canon-SelectTrigger';
|
||||
readonly value: 'canon-SelectValue';
|
||||
readonly icon: 'canon-SelectIcon';
|
||||
readonly popup: 'canon-SelectPopup';
|
||||
readonly item: 'canon-SelectItem';
|
||||
readonly itemIndicator: 'canon-SelectItemIndicator';
|
||||
readonly itemText: 'canon-SelectItemText';
|
||||
readonly description: 'canon-SelectDescription';
|
||||
readonly error: 'canon-SelectError';
|
||||
};
|
||||
readonly dataAttributes: {
|
||||
readonly size: readonly ['small', 'medium'];
|
||||
};
|
||||
};
|
||||
readonly Switch: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-Switch';
|
||||
readonly indicator: 'canon-SwitchIndicator';
|
||||
};
|
||||
};
|
||||
readonly Table: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-TableRoot';
|
||||
readonly header: 'canon-TableHeader';
|
||||
readonly body: 'canon-TableBody';
|
||||
readonly row: 'canon-TableRow';
|
||||
readonly head: 'canon-TableHead';
|
||||
readonly caption: 'canon-TableCaption';
|
||||
readonly cell: 'canon-TableCell';
|
||||
readonly cellText: 'canon-TableCellText';
|
||||
readonly cellLink: 'canon-TableCellLink';
|
||||
readonly cellProfile: 'canon-TableCellProfile';
|
||||
readonly cellProfileAvatar: 'canon-TableCellProfileAvatar';
|
||||
readonly cellProfileAvatarImage: 'canon-TableCellProfileAvatarImage';
|
||||
readonly cellProfileAvatarFallback: 'canon-TableCellProfileAvatarFallback';
|
||||
readonly cellProfileName: 'canon-TableCellProfileName';
|
||||
readonly cellProfileLink: 'canon-TableCellProfileLink';
|
||||
};
|
||||
};
|
||||
readonly Tabs: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-TabsRoot';
|
||||
readonly list: 'canon-TabsList';
|
||||
readonly indicator: 'canon-TabsIndicator';
|
||||
readonly tab: 'canon-TabsTab';
|
||||
readonly panel: 'canon-TabsPanel';
|
||||
};
|
||||
};
|
||||
readonly Text: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-Text';
|
||||
};
|
||||
readonly dataAttributes: {
|
||||
readonly variant: readonly ['subtitle', 'body', 'caption', 'label'];
|
||||
readonly weight: readonly ['regular', 'bold'];
|
||||
readonly color: readonly [
|
||||
'primary',
|
||||
'secondary',
|
||||
'danger',
|
||||
'warning',
|
||||
'success',
|
||||
];
|
||||
readonly truncate: readonly [true, false];
|
||||
};
|
||||
};
|
||||
readonly TextField: {
|
||||
readonly classNames: {
|
||||
readonly root: 'canon-TextField';
|
||||
readonly inputWrapper: 'canon-TextFieldInputWrapper';
|
||||
readonly icon: 'canon-TextFieldIcon';
|
||||
readonly input: 'canon-TextFieldInput';
|
||||
};
|
||||
readonly dataAttributes: {
|
||||
readonly invalid: readonly [true, false];
|
||||
readonly disabled: readonly [true, false];
|
||||
};
|
||||
};
|
||||
readonly Tooltip: {
|
||||
readonly classNames: {
|
||||
readonly trigger: 'canon-TooltipTrigger';
|
||||
readonly positioner: 'canon-TooltipPositioner';
|
||||
readonly popup: 'canon-TooltipPopup';
|
||||
readonly arrow: 'canon-TooltipArrow';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export const Container: ForwardRefExoticComponent<
|
||||
ContainerProps & RefAttributes<HTMLDivElement>
|
||||
@@ -294,6 +538,12 @@ export interface ContainerProps {
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type DataAttributesMap = Record<string, DataAttributeValues>;
|
||||
|
||||
// @public
|
||||
export type DataAttributeValues = readonly (string | number | boolean)[];
|
||||
|
||||
// @public
|
||||
export const DataTable: {
|
||||
Root: <TData>(
|
||||
|
||||
@@ -18,28 +18,36 @@ import { forwardRef, ElementRef } from 'react';
|
||||
import { Avatar as AvatarPrimitive } from '@base-ui-components/react/avatar';
|
||||
import clsx from 'clsx';
|
||||
import { AvatarProps } from './types';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const Avatar = forwardRef<
|
||||
ElementRef<typeof AvatarPrimitive.Root>,
|
||||
AvatarProps
|
||||
>(({ className, src, name, size = 'medium', ...props }, ref) => (
|
||||
<AvatarPrimitive.Root
|
||||
ref={ref}
|
||||
className={clsx('canon-AvatarRoot', className)}
|
||||
data-size={size}
|
||||
{...props}
|
||||
>
|
||||
<AvatarPrimitive.Image className="canon-AvatarImage" src={src} />
|
||||
<AvatarPrimitive.Fallback className="canon-AvatarFallback">
|
||||
{(name || '')
|
||||
.split(' ')
|
||||
.map(word => word[0])
|
||||
.join('')
|
||||
.toLocaleUpperCase('en-US')
|
||||
.slice(0, 2)}
|
||||
</AvatarPrimitive.Fallback>
|
||||
</AvatarPrimitive.Root>
|
||||
));
|
||||
>((props, ref) => {
|
||||
const { className, src, name, size = 'medium', ...rest } = props;
|
||||
const { classNames } = useStyles('Avatar', {
|
||||
size,
|
||||
});
|
||||
|
||||
return (
|
||||
<AvatarPrimitive.Root
|
||||
ref={ref}
|
||||
className={clsx(classNames.root, className)}
|
||||
data-size={size}
|
||||
{...rest}
|
||||
>
|
||||
<AvatarPrimitive.Image className={classNames.image} src={src} />
|
||||
<AvatarPrimitive.Fallback className={classNames.fallback}>
|
||||
{(name || '')
|
||||
.split(' ')
|
||||
.map(word => word[0])
|
||||
.join('')
|
||||
.toLocaleUpperCase('en-US')
|
||||
.slice(0, 2)}
|
||||
</AvatarPrimitive.Fallback>
|
||||
</AvatarPrimitive.Root>
|
||||
);
|
||||
});
|
||||
|
||||
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
||||
|
||||
@@ -24,6 +24,7 @@ import { widthPropDefs } from '../../props/width.props';
|
||||
import { heightPropDefs } from '../../props/height.props';
|
||||
import { positionPropDefs } from '../../props/position.props';
|
||||
import { displayPropDefs } from '../../props/display.props';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const Box = forwardRef<HTMLDivElement, BoxProps>((props, ref) => {
|
||||
@@ -38,11 +39,12 @@ export const Box = forwardRef<HTMLDivElement, BoxProps>((props, ref) => {
|
||||
...boxPropDefs,
|
||||
};
|
||||
|
||||
const { classNames } = useStyles('Box');
|
||||
const { className, style } = extractProps(props, propDefs);
|
||||
|
||||
return createElement(props.as || 'div', {
|
||||
ref,
|
||||
className: clsx('canon-Box', className),
|
||||
className: clsx(classNames.root, className),
|
||||
style,
|
||||
children,
|
||||
});
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
import clsx from 'clsx';
|
||||
import { forwardRef, Ref } from 'react';
|
||||
import { Button as RAButton } from 'react-aria-components';
|
||||
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
|
||||
import type { ButtonProps } from './types';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const Button = forwardRef(
|
||||
@@ -33,15 +33,16 @@ export const Button = forwardRef(
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const responsiveSize = useResponsiveValue(size);
|
||||
const responsiveVariant = useResponsiveValue(variant);
|
||||
const { classNames, dataAttributes } = useStyles('Button', {
|
||||
size,
|
||||
variant,
|
||||
});
|
||||
|
||||
return (
|
||||
<RAButton
|
||||
className={clsx('canon-Button', className)}
|
||||
data-variant={responsiveVariant}
|
||||
data-size={responsiveSize}
|
||||
className={clsx(classNames.root, className)}
|
||||
ref={ref}
|
||||
{...dataAttributes}
|
||||
{...rest}
|
||||
>
|
||||
{iconStart}
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
import clsx from 'clsx';
|
||||
import { forwardRef, Ref } from 'react';
|
||||
import { Button as RAButton } from 'react-aria-components';
|
||||
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
|
||||
import type { ButtonIconProps } from './types';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const ButtonIcon = forwardRef(
|
||||
@@ -32,15 +32,18 @@ export const ButtonIcon = forwardRef(
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const responsiveSize = useResponsiveValue(size);
|
||||
const responsiveVariant = useResponsiveValue(variant);
|
||||
const { classNames, dataAttributes } = useStyles('Button', {
|
||||
size,
|
||||
variant,
|
||||
});
|
||||
|
||||
const { classNames: classNamesButtonIcon } = useStyles('ButtonIcon');
|
||||
|
||||
return (
|
||||
<RAButton
|
||||
className={clsx('canon-Button', 'canon-ButtonIcon', className)}
|
||||
data-variant={responsiveVariant}
|
||||
data-size={responsiveSize}
|
||||
className={clsx(classNames.root, classNamesButtonIcon.root, className)}
|
||||
ref={ref}
|
||||
{...dataAttributes}
|
||||
{...rest}
|
||||
>
|
||||
{icon}
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
import clsx from 'clsx';
|
||||
import { forwardRef, Ref } from 'react';
|
||||
import { Link as RALink } from 'react-aria-components';
|
||||
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
|
||||
import type { ButtonLinkProps } from './types';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const ButtonLink = forwardRef(
|
||||
@@ -33,15 +33,18 @@ export const ButtonLink = forwardRef(
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const responsiveSize = useResponsiveValue(size);
|
||||
const responsiveVariant = useResponsiveValue(variant);
|
||||
const { classNames, dataAttributes } = useStyles('Button', {
|
||||
size,
|
||||
variant,
|
||||
});
|
||||
|
||||
const { classNames: classNamesButtonLink } = useStyles('ButtonLink');
|
||||
|
||||
return (
|
||||
<RALink
|
||||
className={clsx('canon-Button', 'canon-ButtonLink', className)}
|
||||
data-variant={responsiveVariant}
|
||||
data-size={responsiveSize}
|
||||
className={clsx(classNames.root, classNamesButtonLink.root, className)}
|
||||
ref={ref}
|
||||
{...dataAttributes}
|
||||
{...rest}
|
||||
>
|
||||
{iconStart}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { forwardRef } from 'react';
|
||||
import { Checkbox as CheckboxPrimitive } from '@base-ui-components/react/checkbox';
|
||||
import { Icon } from '@backstage/canon';
|
||||
import type { CheckboxProps } from './types';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
import clsx from 'clsx';
|
||||
|
||||
/** @public */
|
||||
@@ -35,10 +36,12 @@ export const Checkbox = forwardRef<HTMLButtonElement, CheckboxProps>(
|
||||
style,
|
||||
} = props;
|
||||
|
||||
const { classNames } = useStyles('Checkbox');
|
||||
|
||||
const checkboxElement = (
|
||||
<CheckboxPrimitive.Root
|
||||
ref={ref}
|
||||
className={clsx('canon-CheckboxRoot', className)}
|
||||
className={clsx(classNames.root, className)}
|
||||
checked={checked}
|
||||
onCheckedChange={onChange}
|
||||
disabled={disabled}
|
||||
@@ -47,14 +50,14 @@ export const Checkbox = forwardRef<HTMLButtonElement, CheckboxProps>(
|
||||
value={value}
|
||||
style={style}
|
||||
>
|
||||
<CheckboxPrimitive.Indicator className="canon-CheckboxIndicator">
|
||||
<CheckboxPrimitive.Indicator className={classNames.indicator}>
|
||||
<Icon name="check" size={12} />
|
||||
</CheckboxPrimitive.Indicator>
|
||||
</CheckboxPrimitive.Root>
|
||||
);
|
||||
|
||||
return label ? (
|
||||
<label className="canon-CheckboxLabel">
|
||||
<label className={classNames.label}>
|
||||
{checkboxElement}
|
||||
{label}
|
||||
</label>
|
||||
|
||||
@@ -17,41 +17,54 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { Collapsible as CollapsiblePrimitive } from '@base-ui-components/react/collapsible';
|
||||
import clsx from 'clsx';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
const CollapsibleRoot = forwardRef<
|
||||
React.ElementRef<typeof CollapsiblePrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CollapsiblePrimitive.Root
|
||||
ref={ref}
|
||||
className={clsx('canon-CollapsibleRoot', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Collapsible');
|
||||
|
||||
return (
|
||||
<CollapsiblePrimitive.Root
|
||||
ref={ref}
|
||||
className={clsx(classNames.root, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
CollapsibleRoot.displayName = CollapsiblePrimitive.Root.displayName;
|
||||
|
||||
const CollapsibleTrigger = forwardRef<
|
||||
React.ElementRef<typeof CollapsiblePrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Trigger>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CollapsiblePrimitive.Trigger
|
||||
ref={ref}
|
||||
className={clsx('canon-CollapsibleTrigger', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Collapsible');
|
||||
|
||||
return (
|
||||
<CollapsiblePrimitive.Trigger
|
||||
ref={ref}
|
||||
className={clsx(classNames.trigger, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
CollapsibleTrigger.displayName = CollapsiblePrimitive.Trigger.displayName;
|
||||
|
||||
const CollapsiblePanel = forwardRef<
|
||||
React.ElementRef<typeof CollapsiblePrimitive.Panel>,
|
||||
React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Panel>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CollapsiblePrimitive.Panel
|
||||
ref={ref}
|
||||
className={clsx('canon-CollapsiblePanel', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Collapsible');
|
||||
|
||||
return (
|
||||
<CollapsiblePrimitive.Panel
|
||||
ref={ref}
|
||||
className={clsx(classNames.panel, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
CollapsiblePanel.displayName = CollapsiblePrimitive.Panel.displayName;
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,12 +20,15 @@ import clsx from 'clsx';
|
||||
import { displayPropDefs } from '../../props/display.props';
|
||||
import { extractProps } from '../../utils/extractProps';
|
||||
import { spacingPropDefs } from '../../props/spacing.props';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const Container = forwardRef<HTMLDivElement, ContainerProps>(
|
||||
(props, ref) => {
|
||||
const { children } = props;
|
||||
|
||||
const { classNames } = useStyles('Container');
|
||||
|
||||
// Create a subset of spacing props that match the interface
|
||||
const containerSpacingProps = {
|
||||
my: spacingPropDefs.my,
|
||||
@@ -44,7 +47,7 @@ export const Container = forwardRef<HTMLDivElement, ContainerProps>(
|
||||
|
||||
return createElement('div', {
|
||||
ref,
|
||||
className: clsx('canon-Container', className),
|
||||
className: clsx(classNames.root, className),
|
||||
style,
|
||||
children,
|
||||
});
|
||||
|
||||
@@ -16,31 +16,31 @@
|
||||
import { Label } from 'react-aria-components';
|
||||
import { forwardRef } from 'react';
|
||||
import type { FieldLabelProps } from './types';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const FieldLabel = forwardRef<HTMLDivElement, FieldLabelProps>(
|
||||
(props: FieldLabelProps, ref) => {
|
||||
const { label, secondaryLabel, description, htmlFor, id, ...rest } = props;
|
||||
|
||||
const { classNames } = useStyles('FieldLabel');
|
||||
|
||||
if (!label) return null;
|
||||
|
||||
return (
|
||||
<div className="canon-FieldLabel" {...rest} ref={ref}>
|
||||
<div className={classNames.root} {...rest} ref={ref}>
|
||||
{label && (
|
||||
<Label className="canon-FieldLabelLabel" htmlFor={htmlFor} id={id}>
|
||||
<Label className={classNames.label} htmlFor={htmlFor} id={id}>
|
||||
{label}
|
||||
{secondaryLabel && (
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="canon-FieldLabelSecondaryLabel"
|
||||
>
|
||||
<span aria-hidden="true" className={classNames.secondaryLabel}>
|
||||
({secondaryLabel})
|
||||
</span>
|
||||
)}
|
||||
</Label>
|
||||
)}
|
||||
{description && (
|
||||
<div className="canon-FieldLabelDescription">{description}</div>
|
||||
<div className={classNames.description}>{description}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -21,6 +21,7 @@ import { flexPropDefs } from './Flex.props';
|
||||
import { extractProps } from '../../utils/extractProps';
|
||||
import { gapPropDefs } from '../../props/gap-props';
|
||||
import { spacingPropDefs } from '../../props/spacing.props';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const Flex = forwardRef<HTMLDivElement, FlexProps>((props, ref) => {
|
||||
@@ -30,11 +31,12 @@ export const Flex = forwardRef<HTMLDivElement, FlexProps>((props, ref) => {
|
||||
...spacingPropDefs,
|
||||
};
|
||||
|
||||
const { classNames } = useStyles('Flex');
|
||||
const { className, style } = extractProps(props, propDefs);
|
||||
|
||||
return createElement('div', {
|
||||
ref,
|
||||
className: clsx('canon-Flex', className),
|
||||
className: clsx(classNames.root, className),
|
||||
style,
|
||||
children: props.children,
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ import { gridItemPropDefs, gridPropDefs } from './Grid.props';
|
||||
import clsx from 'clsx';
|
||||
import type { GridItemProps, GridProps } from './types';
|
||||
import { spacingPropDefs } from '../../props/spacing.props';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
const GridRoot = forwardRef<HTMLDivElement, GridProps>((props, ref) => {
|
||||
const propDefs = {
|
||||
@@ -29,11 +30,13 @@ const GridRoot = forwardRef<HTMLDivElement, GridProps>((props, ref) => {
|
||||
...spacingPropDefs,
|
||||
};
|
||||
|
||||
const { classNames } = useStyles('Grid');
|
||||
|
||||
const { className, style } = extractProps(props, propDefs);
|
||||
|
||||
return createElement('div', {
|
||||
ref,
|
||||
className: clsx('canon-Grid', className),
|
||||
className: clsx(classNames.root, className),
|
||||
style,
|
||||
children: props.children,
|
||||
});
|
||||
@@ -44,11 +47,12 @@ const GridItem = forwardRef<HTMLDivElement, GridItemProps>((props, ref) => {
|
||||
...gridItemPropDefs,
|
||||
};
|
||||
|
||||
const { classNames } = useStyles('Grid');
|
||||
const { className, style } = extractProps(props, propDefs);
|
||||
|
||||
return createElement('div', {
|
||||
ref,
|
||||
className: clsx('canon-GridItem', className),
|
||||
className: clsx(classNames.item, className),
|
||||
style,
|
||||
children: props.children,
|
||||
});
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
import { forwardRef } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
|
||||
import type { ElementType } from 'react';
|
||||
import type { HeadingProps } from './types';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
function HeadingComponent<T extends ElementType = 'h1'>(
|
||||
{
|
||||
@@ -34,16 +34,17 @@ function HeadingComponent<T extends ElementType = 'h1'>(
|
||||
) {
|
||||
const Component = as || 'h1';
|
||||
|
||||
const responsiveVariant = useResponsiveValue(variant);
|
||||
const responsiveColor = useResponsiveValue(color);
|
||||
const { classNames, dataAttributes } = useStyles('Heading', {
|
||||
variant,
|
||||
color,
|
||||
truncate,
|
||||
});
|
||||
|
||||
return (
|
||||
<Component
|
||||
ref={ref}
|
||||
className={clsx('canon-Heading', className)}
|
||||
data-variant={responsiveVariant}
|
||||
data-color={responsiveColor}
|
||||
data-truncate={truncate}
|
||||
className={clsx(classNames.root, className)}
|
||||
{...dataAttributes}
|
||||
style={style}
|
||||
{...restProps}
|
||||
/>
|
||||
|
||||
@@ -18,6 +18,7 @@ import { ComponentType } from 'react';
|
||||
import { useIcons } from './context';
|
||||
import type { IconProps } from './types';
|
||||
import clsx from 'clsx';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const Icon = (props: IconProps) => {
|
||||
@@ -31,9 +32,11 @@ export const Icon = (props: IconProps) => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { classNames } = useStyles('Icon');
|
||||
|
||||
return (
|
||||
<CanonIcon
|
||||
className={clsx('canon-Icon', className)}
|
||||
className={clsx(classNames.root, className)}
|
||||
style={{
|
||||
...(size ? { width: size, height: size } : {}),
|
||||
...style,
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
import { useRef, forwardRef } from 'react';
|
||||
import { useRender } from '@base-ui-components/react/use-render';
|
||||
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
|
||||
import clsx from 'clsx';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
import type { LinkProps } from './types';
|
||||
|
||||
@@ -31,16 +31,14 @@ export const Link = forwardRef<HTMLElement, LinkProps>((props, ref) => {
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
const responsiveVariant = useResponsiveValue(variant);
|
||||
const responsiveWeight = useResponsiveValue(weight);
|
||||
const { classNames, dataAttributes } = useStyles('Link', { variant, weight });
|
||||
const internalRef = useRef<HTMLElement | null>(null);
|
||||
|
||||
const { renderElement } = useRender({
|
||||
render,
|
||||
props: {
|
||||
className: clsx('canon-Link', className),
|
||||
['data-variant']: responsiveVariant,
|
||||
['data-weight']: responsiveWeight,
|
||||
className: clsx(classNames.root, className),
|
||||
...dataAttributes,
|
||||
...restProps,
|
||||
},
|
||||
refs: [ref, internalRef],
|
||||
|
||||
@@ -20,190 +20,255 @@ import clsx from 'clsx';
|
||||
import { MenuComponent } from './types';
|
||||
import { Combobox } from './Combobox';
|
||||
import { Icon } from '../Icon';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
const MenuTrigger = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Trigger>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuTrigger', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={clsx(classNames.trigger, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuTrigger.displayName = MenuPrimitive.Trigger.displayName;
|
||||
|
||||
const MenuBackdrop = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.Backdrop>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Backdrop>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.Backdrop
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuBackdrop', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.Backdrop
|
||||
ref={ref}
|
||||
className={clsx(classNames.backdrop, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuBackdrop.displayName = MenuPrimitive.Backdrop.displayName;
|
||||
|
||||
const MenuPositioner = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.Positioner>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Positioner>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.Positioner
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuPositioner', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.Positioner
|
||||
ref={ref}
|
||||
className={clsx(classNames.positioner, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuPositioner.displayName = MenuPrimitive.Positioner.displayName;
|
||||
|
||||
const MenuPopup = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.Popup>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Popup>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.Popup
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuPopup', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.Popup
|
||||
ref={ref}
|
||||
className={clsx(classNames.popup, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuPopup.displayName = MenuPrimitive.Popup.displayName;
|
||||
|
||||
const MenuArrow = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.Arrow>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Arrow>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.Arrow
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuArrow', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.Arrow
|
||||
ref={ref}
|
||||
className={clsx(classNames.arrow, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuArrow.displayName = MenuPrimitive.Arrow.displayName;
|
||||
|
||||
const MenuItem = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuItem', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={clsx(classNames.item, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuItem.displayName = MenuPrimitive.Item.displayName;
|
||||
|
||||
const MenuGroup = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.Group>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Group>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.Group
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuGroup', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.Group
|
||||
ref={ref}
|
||||
className={clsx(classNames.group, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuGroup.displayName = MenuPrimitive.Group.displayName;
|
||||
|
||||
const MenuGroupLabel = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.GroupLabel>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.GroupLabel>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.GroupLabel
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuGroupLabel', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.GroupLabel
|
||||
ref={ref}
|
||||
className={clsx(classNames.groupLabel, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuGroupLabel.displayName = MenuPrimitive.GroupLabel.displayName;
|
||||
|
||||
const MenuRadioGroup = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.RadioGroup>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioGroup>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.RadioGroup
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuRadioGroup', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.RadioGroup
|
||||
ref={ref}
|
||||
className={clsx(classNames.radioGroup, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuRadioGroup.displayName = MenuPrimitive.RadioGroup.displayName;
|
||||
|
||||
const MenuRadioItem = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioItem>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuRadioItem', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={clsx(classNames.radioItem, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuRadioItem.displayName = MenuPrimitive.RadioItem.displayName;
|
||||
|
||||
const MenuRadioItemIndicator = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.RadioItemIndicator>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioItemIndicator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.RadioItemIndicator
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuRadioItemIndicator', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.RadioItemIndicator
|
||||
ref={ref}
|
||||
className={clsx(classNames.radioItemIndicator, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuRadioItemIndicator.displayName =
|
||||
MenuPrimitive.RadioItemIndicator.displayName;
|
||||
|
||||
const MenuCheckboxItem = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.CheckboxItem>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuCheckboxItem', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={clsx(classNames.checkboxItem, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuCheckboxItem.displayName = MenuPrimitive.CheckboxItem.displayName;
|
||||
|
||||
const MenuCheckboxItemIndicator = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.CheckboxItemIndicator>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.CheckboxItemIndicator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.CheckboxItemIndicator
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuCheckboxItemIndicator', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.CheckboxItemIndicator
|
||||
ref={ref}
|
||||
className={clsx(classNames.checkboxItemIndicator, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuCheckboxItemIndicator.displayName =
|
||||
MenuPrimitive.CheckboxItemIndicator.displayName;
|
||||
|
||||
const MenuSubmenuTrigger = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.SubmenuTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.SubmenuTrigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<MenuPrimitive.SubmenuTrigger
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuSubmenuTrigger', className)}
|
||||
{...props}
|
||||
>
|
||||
<div>{children}</div>
|
||||
<Icon aria-label="Submenu indicator icon" name="chevron-right" size={20} />
|
||||
</MenuPrimitive.SubmenuTrigger>
|
||||
));
|
||||
>(({ className, children, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.SubmenuTrigger
|
||||
ref={ref}
|
||||
className={clsx(classNames.submenuTrigger, className)}
|
||||
{...props}
|
||||
>
|
||||
<div>{children}</div>
|
||||
<Icon
|
||||
aria-label="Submenu indicator icon"
|
||||
name="chevron-right"
|
||||
size={20}
|
||||
/>
|
||||
</MenuPrimitive.SubmenuTrigger>
|
||||
);
|
||||
});
|
||||
MenuSubmenuTrigger.displayName = MenuPrimitive.SubmenuTrigger.displayName;
|
||||
|
||||
const MenuSeparator = forwardRef<
|
||||
React.ElementRef<typeof MenuPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={clsx('canon-MenuSeparator', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Menu');
|
||||
|
||||
return (
|
||||
<MenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={clsx(classNames.separator, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MenuSeparator.displayName = MenuPrimitive.Separator.displayName;
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
import clsx from 'clsx';
|
||||
import { FieldLabel } from '../FieldLabel';
|
||||
import { FieldError } from '../FieldError';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
import type { RadioGroupProps, RadioProps } from './types';
|
||||
|
||||
@@ -40,6 +41,8 @@ export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const { classNames } = useStyles('RadioGroup');
|
||||
|
||||
useEffect(() => {
|
||||
if (!label && !ariaLabel && !ariaLabelledBy) {
|
||||
console.warn(
|
||||
@@ -54,7 +57,7 @@ export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
||||
|
||||
return (
|
||||
<AriaRadioGroup
|
||||
className={clsx('canon-RadioGroup', className)}
|
||||
className={clsx(classNames.root, className)}
|
||||
aria-label={ariaLabel}
|
||||
aria-labelledby={ariaLabelledBy}
|
||||
{...rest}
|
||||
@@ -65,7 +68,7 @@ export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
||||
secondaryLabel={secondaryLabelText}
|
||||
description={description}
|
||||
/>
|
||||
<div className="canon-RadioGroupContent">{children}</div>
|
||||
<div className={classNames.content}>{children}</div>
|
||||
<FieldError />
|
||||
</AriaRadioGroup>
|
||||
);
|
||||
@@ -78,8 +81,14 @@ RadioGroup.displayName = 'RadioGroup';
|
||||
export const Radio = forwardRef<HTMLLabelElement, RadioProps>((props, ref) => {
|
||||
const { className, ...rest } = props;
|
||||
|
||||
const { classNames } = useStyles('RadioGroup');
|
||||
|
||||
return (
|
||||
<AriaRadio className={clsx('canon-Radio', className)} {...rest} ref={ref} />
|
||||
<AriaRadio
|
||||
className={clsx(classNames.radio, className)}
|
||||
{...rest}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -17,53 +17,70 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { ScrollArea as ScrollAreaPrimitive } from '@base-ui-components/react/scroll-area';
|
||||
import clsx from 'clsx';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
const ScrollAreaRoot = forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Root
|
||||
ref={ref}
|
||||
className={clsx('canon-ScrollAreaRoot', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('ScrollArea');
|
||||
|
||||
return (
|
||||
<ScrollAreaPrimitive.Root
|
||||
ref={ref}
|
||||
className={clsx(classNames.root, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
ScrollAreaRoot.displayName = ScrollAreaPrimitive.Root.displayName;
|
||||
|
||||
const ScrollAreaViewport = forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Viewport>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Viewport>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Viewport
|
||||
ref={ref}
|
||||
className={clsx('canon-ScrollAreaViewport', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('ScrollArea');
|
||||
|
||||
return (
|
||||
<ScrollAreaPrimitive.Viewport
|
||||
ref={ref}
|
||||
className={clsx(classNames.viewport, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
ScrollAreaViewport.displayName = ScrollAreaPrimitive.Viewport.displayName;
|
||||
|
||||
const ScrollAreaScrollbar = forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Scrollbar>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Scrollbar>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Scrollbar
|
||||
ref={ref}
|
||||
className={clsx('canon-ScrollAreaScrollbar', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('ScrollArea');
|
||||
|
||||
return (
|
||||
<ScrollAreaPrimitive.Scrollbar
|
||||
ref={ref}
|
||||
className={clsx(classNames.scrollbar, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
ScrollAreaScrollbar.displayName = ScrollAreaPrimitive.Scrollbar.displayName;
|
||||
|
||||
const ScrollAreaThumb = forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Thumb>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Thumb>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Thumb
|
||||
ref={ref}
|
||||
className={clsx('canon-ScrollAreaThumb', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('ScrollArea');
|
||||
|
||||
return (
|
||||
<ScrollAreaPrimitive.Thumb
|
||||
ref={ref}
|
||||
className={clsx(classNames.thumb, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
ScrollAreaThumb.displayName = ScrollAreaPrimitive.Thumb.displayName;
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -20,7 +20,7 @@ import { Icon } from '../Icon';
|
||||
import clsx from 'clsx';
|
||||
import './Select.styles.css';
|
||||
import { SelectProps } from './types';
|
||||
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const Select = forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
|
||||
@@ -37,8 +37,9 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
// Get the responsive value for the variant
|
||||
const responsiveSize = useResponsiveValue(size);
|
||||
const { classNames, dataAttributes } = useStyles('Select', {
|
||||
size,
|
||||
});
|
||||
|
||||
// Generate unique IDs for accessibility
|
||||
const selectId = useId();
|
||||
@@ -58,7 +59,7 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={clsx('canon-Select', className)} style={style} ref={ref}>
|
||||
<div className={clsx(classNames.root, className)} style={style} ref={ref}>
|
||||
{label && (
|
||||
<label
|
||||
className="canon-SelectLabel"
|
||||
@@ -68,7 +69,7 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
|
||||
>
|
||||
{label}
|
||||
{required && (
|
||||
<span aria-hidden="true" className="canon-SelectRequired">
|
||||
<span aria-hidden="true" className={classNames.required}>
|
||||
(Required)
|
||||
</span>
|
||||
)}
|
||||
@@ -78,33 +79,35 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
|
||||
<SelectPrimitive.Trigger
|
||||
ref={triggerRef}
|
||||
id={selectId}
|
||||
className="canon-SelectTrigger"
|
||||
data-size={responsiveSize}
|
||||
className={classNames.trigger}
|
||||
data-size={dataAttributes['data-size']}
|
||||
data-invalid={error}
|
||||
>
|
||||
<SelectPrimitive.Value
|
||||
className="canon-SelectValue"
|
||||
className={classNames.value}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
<SelectPrimitive.Icon className="canon-SelectIcon">
|
||||
<SelectPrimitive.Icon className={classNames.icon}>
|
||||
<Icon name="chevron-down" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Backdrop />
|
||||
<SelectPrimitive.Positioner>
|
||||
<SelectPrimitive.Popup className="canon-SelectPopup">
|
||||
<SelectPrimitive.Popup className={classNames.popup}>
|
||||
{options?.map(option => (
|
||||
<SelectPrimitive.Item
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
disabled={option.disabled}
|
||||
className="canon-SelectItem"
|
||||
className={classNames.item}
|
||||
>
|
||||
<SelectPrimitive.ItemIndicator className="canon-SelectItemIndicator">
|
||||
<SelectPrimitive.ItemIndicator
|
||||
className={classNames.itemIndicator}
|
||||
>
|
||||
<Icon name="check" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
<SelectPrimitive.ItemText className="canon-SelectItemText">
|
||||
<SelectPrimitive.ItemText className={classNames.itemText}>
|
||||
{option.label}
|
||||
</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
@@ -114,12 +117,12 @@ export const Select = forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
|
||||
</SelectPrimitive.Portal>
|
||||
</SelectPrimitive.Root>
|
||||
{description && (
|
||||
<p className="canon-SelectDescription" id={descriptionId}>
|
||||
<p className={classNames.description} id={descriptionId}>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
{error && (
|
||||
<p className="canon-SelectError" id={errorId} role="alert">
|
||||
<p className={classNames.error} id={errorId} role="alert">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { Switch as AriaSwitch } from 'react-aria-components';
|
||||
import type { SwitchProps } from './types';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const Switch = forwardRef<HTMLLabelElement, SwitchProps>(
|
||||
({ label, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Switch');
|
||||
|
||||
return (
|
||||
<AriaSwitch className="canon-Switch" ref={ref} {...props}>
|
||||
<div className="canon-SwitchIndicator" />
|
||||
<AriaSwitch className={classNames.root} ref={ref} {...props}>
|
||||
<div className={classNames.indicator} />
|
||||
{label}
|
||||
</AriaSwitch>
|
||||
);
|
||||
|
||||
@@ -20,63 +20,88 @@ import { TableCell } from './TableCell/TableCell';
|
||||
import { TableCellText } from './TableCellText/TableCellText';
|
||||
import { TableCellLink } from './TableCellLink/TableCellLink';
|
||||
import { TableCellProfile } from './TableCellProfile/TableCellProfile';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
const TableRoot = forwardRef<
|
||||
HTMLTableElement,
|
||||
React.HTMLAttributes<HTMLTableElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<table ref={ref} className={clsx('canon-TableRoot', className)} {...props} />
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Table');
|
||||
|
||||
return (
|
||||
<table ref={ref} className={clsx(classNames.root, className)} {...props} />
|
||||
);
|
||||
});
|
||||
TableRoot.displayName = 'TableRoot';
|
||||
|
||||
const TableHeader = forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<thead
|
||||
ref={ref}
|
||||
className={clsx('canon-TableHeader', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Table');
|
||||
|
||||
return (
|
||||
<thead
|
||||
ref={ref}
|
||||
className={clsx(classNames.header, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
TableHeader.displayName = 'TableHeader';
|
||||
|
||||
const TableBody = forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tbody ref={ref} className={clsx('canon-TableBody', className)} {...props} />
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Table');
|
||||
|
||||
return (
|
||||
<tbody ref={ref} className={clsx(classNames.body, className)} {...props} />
|
||||
);
|
||||
});
|
||||
TableBody.displayName = 'TableBody';
|
||||
|
||||
const TableRow = forwardRef<
|
||||
HTMLTableRowElement,
|
||||
React.HTMLAttributes<HTMLTableRowElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tr ref={ref} className={clsx('canon-TableRow', className)} {...props}>
|
||||
{props.children}
|
||||
</tr>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Table');
|
||||
|
||||
return (
|
||||
<tr ref={ref} className={clsx(classNames.row, className)} {...props}>
|
||||
{props.children}
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
TableRow.displayName = 'TableRow';
|
||||
|
||||
const TableHead = forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.ThHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<th ref={ref} className={clsx('canon-TableHead', className)} {...props} />
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Table');
|
||||
|
||||
return (
|
||||
<th ref={ref} className={clsx(classNames.head, className)} {...props} />
|
||||
);
|
||||
});
|
||||
TableHead.displayName = 'TableHead';
|
||||
|
||||
const TableCaption = forwardRef<
|
||||
HTMLTableCaptionElement,
|
||||
React.HTMLAttributes<HTMLTableCaptionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<caption
|
||||
ref={ref}
|
||||
className={clsx('canon-TableCaption', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Table');
|
||||
|
||||
return (
|
||||
<caption
|
||||
ref={ref}
|
||||
className={clsx(classNames.caption, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
TableCaption.displayName = 'TableCaption';
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,14 +16,19 @@
|
||||
|
||||
import { forwardRef } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { useStyles } from '../../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
const TableCell = forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.TdHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<td ref={ref} className={clsx('canon-TableCell', className)} {...props} />
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Table');
|
||||
|
||||
return (
|
||||
<td ref={ref} className={clsx(classNames.cell, className)} {...props} />
|
||||
);
|
||||
});
|
||||
TableCell.displayName = 'TableCell';
|
||||
|
||||
export { TableCell };
|
||||
|
||||
@@ -19,27 +19,32 @@ import clsx from 'clsx';
|
||||
import { TableCellLinkProps } from './types';
|
||||
import { Text } from '../../Text/Text';
|
||||
import { Link } from '../../Link/Link';
|
||||
import { useStyles } from '../../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
const TableCellLink = forwardRef<HTMLDivElement, TableCellLinkProps>(
|
||||
({ className, title, description, href, render, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx('canon-TableCellLink', className)}
|
||||
{...props}
|
||||
>
|
||||
{title && (
|
||||
<Link href={href} render={render}>
|
||||
{title}
|
||||
</Link>
|
||||
)}
|
||||
{description && (
|
||||
<Text variant="body" color="secondary">
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
({ className, title, description, href, render, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Table');
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx(classNames.cellLink, className)}
|
||||
{...props}
|
||||
>
|
||||
{title && (
|
||||
<Link href={href} render={render}>
|
||||
{title}
|
||||
</Link>
|
||||
)}
|
||||
{description && (
|
||||
<Text variant="body" color="secondary">
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
TableCellLink.displayName = 'TableCellLink';
|
||||
|
||||
|
||||
@@ -20,40 +20,45 @@ import { TableCellProfileProps } from './types';
|
||||
import { Text } from '../../Text/Text';
|
||||
import { Link } from '../../Link/Link';
|
||||
import { Avatar } from '@base-ui-components/react/avatar';
|
||||
import { useStyles } from '../../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
const TableCellProfile = forwardRef<HTMLDivElement, TableCellProfileProps>(
|
||||
({ className, src, name, to, withImage = true, ...rest }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx('canon-TableCellProfile', className)}
|
||||
{...rest}
|
||||
>
|
||||
{withImage && (
|
||||
<Avatar.Root className="canon-TableCellProfileAvatar">
|
||||
<Avatar.Image
|
||||
src={src}
|
||||
width="20"
|
||||
height="20"
|
||||
className="canon-TableCellProfileAvatarImage"
|
||||
/>
|
||||
<Avatar.Fallback className="canon-TableCellProfileAvatarFallback">
|
||||
{(name || '')
|
||||
.split(' ')
|
||||
.map(word => word[0])
|
||||
.join('')
|
||||
.toLocaleUpperCase('en-US')
|
||||
.slice(0, 1)}
|
||||
</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
)}
|
||||
{name && to ? (
|
||||
<Link to={to}>{name}</Link>
|
||||
) : (
|
||||
<Text variant="body">{name}</Text>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
({ className, src, name, to, withImage = true, ...rest }, ref) => {
|
||||
const { classNames } = useStyles('Table');
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx(classNames.cellProfile, className)}
|
||||
{...rest}
|
||||
>
|
||||
{withImage && (
|
||||
<Avatar.Root className={classNames.cellProfileAvatar}>
|
||||
<Avatar.Image
|
||||
src={src}
|
||||
width="20"
|
||||
height="20"
|
||||
className={classNames.cellProfileAvatarImage}
|
||||
/>
|
||||
<Avatar.Fallback className={classNames.cellProfileAvatarFallback}>
|
||||
{(name || '')
|
||||
.split(' ')
|
||||
.map(word => word[0])
|
||||
.join('')
|
||||
.toLocaleUpperCase('en-US')
|
||||
.slice(0, 1)}
|
||||
</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
)}
|
||||
{name && to ? (
|
||||
<Link to={to}>{name}</Link>
|
||||
) : (
|
||||
<Text variant="body">{name}</Text>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
TableCellProfile.displayName = 'TableCellProfile';
|
||||
|
||||
|
||||
@@ -18,23 +18,28 @@ import { forwardRef } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { TableCellTextProps } from './types';
|
||||
import { Text } from '../../Text/Text';
|
||||
import { useStyles } from '../../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
const TableCellText = forwardRef<HTMLDivElement, TableCellTextProps>(
|
||||
({ className, title, description, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx('canon-TableCellText', className)}
|
||||
{...props}
|
||||
>
|
||||
{title && <Text variant="body">{title}</Text>}
|
||||
{description && (
|
||||
<Text variant="body" color="secondary">
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
({ className, title, description, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Table');
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx(classNames.cellText, className)}
|
||||
{...props}
|
||||
>
|
||||
{title && <Text variant="body">{title}</Text>}
|
||||
{description && (
|
||||
<Text variant="body" color="secondary">
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
TableCellText.displayName = 'TableCellText';
|
||||
|
||||
|
||||
@@ -18,56 +18,73 @@ import { forwardRef } from 'react';
|
||||
import { Tabs as TabsPrimitive } from '@base-ui-components/react/tabs';
|
||||
import type { TabsRootWithoutOrientation } from './types';
|
||||
import clsx from 'clsx';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
const TabsRoot = forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Root>,
|
||||
TabsRootWithoutOrientation
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Root
|
||||
ref={ref}
|
||||
className={clsx('canon-TabsRoot', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Tabs');
|
||||
|
||||
return (
|
||||
<TabsPrimitive.Root
|
||||
ref={ref}
|
||||
className={clsx(classNames.root, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
TabsRoot.displayName = TabsPrimitive.Root.displayName;
|
||||
|
||||
const TabsList = forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={clsx('canon-TabsList', className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<TabsPrimitive.Indicator className="canon-TabsIndicator" />
|
||||
</TabsPrimitive.List>
|
||||
));
|
||||
>(({ className, children, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Tabs');
|
||||
|
||||
return (
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={clsx(classNames.list, className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<TabsPrimitive.Indicator className={classNames.indicator} />
|
||||
</TabsPrimitive.List>
|
||||
);
|
||||
});
|
||||
TabsList.displayName = TabsPrimitive.List.displayName;
|
||||
|
||||
const TabsTab = forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Tab>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Tab>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Tab
|
||||
ref={ref}
|
||||
className={clsx('canon-TabsTab', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Tabs');
|
||||
|
||||
return (
|
||||
<TabsPrimitive.Tab
|
||||
ref={ref}
|
||||
className={clsx(classNames.tab, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
TabsTab.displayName = TabsPrimitive.Tab.displayName;
|
||||
|
||||
const TabsPanel = forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Panel>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Panel>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Panel
|
||||
ref={ref}
|
||||
className={clsx('canon-TabsPanel', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Tabs');
|
||||
|
||||
return (
|
||||
<TabsPrimitive.Panel
|
||||
ref={ref}
|
||||
className={clsx(classNames.panel, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
TabsPanel.displayName = TabsPrimitive.Panel.displayName;
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
|
||||
import { forwardRef } from 'react';
|
||||
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
|
||||
import clsx from 'clsx';
|
||||
import type { ElementType } from 'react';
|
||||
import type { TextProps } from './types';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
function TextComponent<T extends ElementType = 'p'>(
|
||||
{
|
||||
@@ -35,19 +35,18 @@ function TextComponent<T extends ElementType = 'p'>(
|
||||
) {
|
||||
const Component = as || 'p';
|
||||
|
||||
// Get the responsive values for the variant and weight
|
||||
const responsiveVariant = useResponsiveValue(variant);
|
||||
const responsiveWeight = useResponsiveValue(weight);
|
||||
const responsiveColor = useResponsiveValue(color);
|
||||
const { classNames, dataAttributes } = useStyles('Text', {
|
||||
variant,
|
||||
weight,
|
||||
color,
|
||||
truncate,
|
||||
});
|
||||
|
||||
return (
|
||||
<Component
|
||||
ref={ref}
|
||||
className={clsx('canon-Text', className)}
|
||||
data-variant={responsiveVariant}
|
||||
data-weight={responsiveWeight}
|
||||
data-color={responsiveColor}
|
||||
data-truncate={truncate}
|
||||
className={clsx(classNames.root, className)}
|
||||
{...dataAttributes}
|
||||
style={style}
|
||||
{...restProps}
|
||||
/>
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
|
||||
import { forwardRef, useEffect } from 'react';
|
||||
import { Input, TextField as AriaTextField } from 'react-aria-components';
|
||||
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
|
||||
import clsx from 'clsx';
|
||||
import { FieldLabel } from '../FieldLabel';
|
||||
import { FieldError } from '../FieldError';
|
||||
|
||||
import type { TextFieldProps } from './types';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(
|
||||
@@ -49,7 +49,9 @@ export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(
|
||||
}, [label, ariaLabel, ariaLabelledBy]);
|
||||
|
||||
// Get the responsive value for the variant
|
||||
const responsiveSize = useResponsiveValue(size);
|
||||
const { classNames, dataAttributes } = useStyles('TextField', {
|
||||
size,
|
||||
});
|
||||
|
||||
// If a secondary label is provided, use it. Otherwise, use 'Required' if the field is required.
|
||||
const secondaryLabelText =
|
||||
@@ -57,8 +59,8 @@ export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(
|
||||
|
||||
return (
|
||||
<AriaTextField
|
||||
className={clsx('canon-TextField', className)}
|
||||
data-size={responsiveSize}
|
||||
className={clsx(classNames.root, className)}
|
||||
{...dataAttributes}
|
||||
aria-label={ariaLabel}
|
||||
aria-labelledby={ariaLabelledBy}
|
||||
{...rest}
|
||||
@@ -69,18 +71,21 @@ export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(
|
||||
secondaryLabel={secondaryLabelText}
|
||||
description={description}
|
||||
/>
|
||||
<div className="canon-TextFieldInputWrapper" data-size={responsiveSize}>
|
||||
<div
|
||||
className={classNames.inputWrapper}
|
||||
data-size={dataAttributes['data-size']}
|
||||
>
|
||||
{icon && (
|
||||
<div
|
||||
className="canon-TextFieldIcon"
|
||||
data-size={responsiveSize}
|
||||
className={classNames.icon}
|
||||
data-size={dataAttributes['data-size']}
|
||||
aria-hidden="true"
|
||||
>
|
||||
{icon}
|
||||
</div>
|
||||
)}
|
||||
<Input
|
||||
className="canon-TextFieldInput"
|
||||
className={classNames.input}
|
||||
{...(icon && { 'data-icon': true })}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
|
||||
@@ -17,68 +17,85 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { Tooltip as TooltipPrimitive } from '@base-ui-components/react/tooltip';
|
||||
import clsx from 'clsx';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
const TooltipTrigger = forwardRef<
|
||||
React.ElementRef<typeof TooltipPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TooltipPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={clsx('canon-TooltipTrigger', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Tooltip');
|
||||
|
||||
return (
|
||||
<TooltipPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={clsx(classNames.trigger, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
TooltipTrigger.displayName = TooltipPrimitive.Trigger.displayName;
|
||||
|
||||
const TooltipPositioner = forwardRef<
|
||||
React.ElementRef<typeof TooltipPrimitive.Positioner>,
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Positioner>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TooltipPrimitive.Positioner
|
||||
ref={ref}
|
||||
className={clsx('canon-TooltipPositioner', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Tooltip');
|
||||
|
||||
return (
|
||||
<TooltipPrimitive.Positioner
|
||||
ref={ref}
|
||||
className={clsx(classNames.positioner, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
TooltipPositioner.displayName = TooltipPrimitive.Positioner.displayName;
|
||||
|
||||
const TooltipPopup = forwardRef<
|
||||
React.ElementRef<typeof TooltipPrimitive.Popup>,
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Popup>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TooltipPrimitive.Popup
|
||||
ref={ref}
|
||||
className={clsx('canon-TooltipPopup', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Tooltip');
|
||||
|
||||
return (
|
||||
<TooltipPrimitive.Popup
|
||||
ref={ref}
|
||||
className={clsx(classNames.popup, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
TooltipPopup.displayName = TooltipPrimitive.Popup.displayName;
|
||||
|
||||
const TooltipArrow = forwardRef<
|
||||
React.ElementRef<typeof TooltipPrimitive.Arrow>,
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TooltipPrimitive.Arrow
|
||||
ref={ref}
|
||||
className={clsx('canon-TooltipArrow', className)}
|
||||
{...props}
|
||||
>
|
||||
<svg width="20" height="10" viewBox="0 0 20 10" fill="none">
|
||||
<path
|
||||
d="M9.66437 2.60207L4.80758 6.97318C4.07308 7.63423 3.11989 8 2.13172 8H0V10H20V8H18.5349C17.5468 8 16.5936 7.63423 15.8591 6.97318L11.0023 2.60207C10.622 2.2598 10.0447 2.25979 9.66437 2.60207Z"
|
||||
className="canon-TooltipArrow-fill"
|
||||
/>
|
||||
<path
|
||||
d="M8.99542 1.85876C9.75604 1.17425 10.9106 1.17422 11.6713 1.85878L16.5281 6.22989C17.0789 6.72568 17.7938 7.00001 18.5349 7.00001L15.89 7L11.0023 2.60207C10.622 2.2598 10.0447 2.2598 9.66436 2.60207L4.77734 7L2.13171 7.00001C2.87284 7.00001 3.58774 6.72568 4.13861 6.22989L8.99542 1.85876Z"
|
||||
className="canon-TooltipArrow-outer-stroke"
|
||||
/>
|
||||
<path
|
||||
d="M10.3333 3.34539L5.47654 7.71648C4.55842 8.54279 3.36693 9 2.13172 9H0V8H2.13172C3.11989 8 4.07308 7.63423 4.80758 6.97318L9.66437 2.60207C10.0447 2.25979 10.622 2.2598 11.0023 2.60207L15.8591 6.97318C16.5936 7.63423 17.5468 8 18.5349 8H20V9H18.5349C17.2998 9 16.1083 8.54278 15.1901 7.71648L10.3333 3.34539Z"
|
||||
className="canon-TooltipArrow-inner-stroke"
|
||||
/>
|
||||
</svg>
|
||||
</TooltipPrimitive.Arrow>
|
||||
));
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { classNames } = useStyles('Tooltip');
|
||||
|
||||
return (
|
||||
<TooltipPrimitive.Arrow
|
||||
ref={ref}
|
||||
className={clsx(classNames.arrow, className)}
|
||||
{...props}
|
||||
>
|
||||
<svg width="20" height="10" viewBox="0 0 20 10" fill="none">
|
||||
<path
|
||||
d="M9.66437 2.60207L4.80758 6.97318C4.07308 7.63423 3.11989 8 2.13172 8H0V10H20V8H18.5349C17.5468 8 16.5936 7.63423 15.8591 6.97318L11.0023 2.60207C10.622 2.2598 10.0447 2.25979 9.66437 2.60207Z"
|
||||
className="canon-TooltipArrow-fill"
|
||||
/>
|
||||
<path
|
||||
d="M8.99542 1.85876C9.75604 1.17425 10.9106 1.17422 11.6713 1.85878L16.5281 6.22989C17.0789 6.72568 17.7938 7.00001 18.5349 7.00001L15.89 7L11.0023 2.60207C10.622 2.2598 10.0447 2.2598 9.66436 2.60207L4.77734 7L2.13171 7.00001C2.87284 7.00001 3.58774 6.72568 4.13861 6.22989L8.99542 1.85876Z"
|
||||
className="canon-TooltipArrow-outer-stroke"
|
||||
/>
|
||||
<path
|
||||
d="M10.3333 3.34539L5.47654 7.71648C4.55842 8.54279 3.36693 9 2.13172 9H0V8H2.13172C3.11989 8 4.07308 7.63423 4.80758 6.97318L9.66437 2.60207C10.0447 2.25979 10.622 2.2598 11.0023 2.60207L15.8591 6.97318C16.5936 7.63423 17.5468 8 18.5349 8H20V9H18.5349C17.2998 9 16.1083 8.54278 15.1901 7.71648L10.3333 3.34539Z"
|
||||
className="canon-TooltipArrow-inner-stroke"
|
||||
/>
|
||||
</svg>
|
||||
</TooltipPrimitive.Arrow>
|
||||
);
|
||||
});
|
||||
TooltipArrow.displayName = TooltipPrimitive.Arrow.displayName;
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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 { useBreakpoint, breakpoints } from './useBreakpoint';
|
||||
import { componentDefinitions } from '../utils/componentDefinitions';
|
||||
import type { ComponentDefinitionName, ComponentClassNames } from '../types';
|
||||
|
||||
/**
|
||||
* Resolve a responsive value based on the current breakpoint
|
||||
* @param value - The responsive value (string or object with breakpoint keys)
|
||||
* @param breakpoint - The current breakpoint
|
||||
* @returns The resolved value for the current breakpoint
|
||||
*/
|
||||
function resolveResponsiveValue(
|
||||
value: string | Record<string, string>,
|
||||
breakpoint: string,
|
||||
): string | undefined {
|
||||
if (typeof value === 'string') {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
const index = breakpoints.findIndex(b => b.id === breakpoint);
|
||||
|
||||
// Look for value at current breakpoint or smaller
|
||||
for (let i = index; i >= 0; i--) {
|
||||
if (value[breakpoints[i].id]) {
|
||||
return value[breakpoints[i].id];
|
||||
}
|
||||
}
|
||||
|
||||
// If no value found, check from smallest breakpoint up
|
||||
for (let i = 0; i < breakpoints.length; i++) {
|
||||
if (value[breakpoints[i].id]) {
|
||||
return value[breakpoints[i].id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* React hook to get class names and data attributes for a component with responsive support
|
||||
* @param componentName - The name of the component
|
||||
* @param props - Object with prop values (can be responsive)
|
||||
* @returns Object with classNames and dataAttributes
|
||||
*/
|
||||
export function useStyles<T extends ComponentDefinitionName>(
|
||||
componentName: T,
|
||||
props: Record<string, any> = {},
|
||||
): {
|
||||
classNames: ComponentClassNames<T>;
|
||||
dataAttributes: Record<string, string>;
|
||||
resolvedProps: Record<string, string>;
|
||||
} {
|
||||
const { breakpoint } = useBreakpoint();
|
||||
const classNames = componentDefinitions[componentName]
|
||||
.classNames as ComponentClassNames<T>;
|
||||
|
||||
// Resolve responsive values and generate data attributes
|
||||
const dataAttributes: Record<string, string> = {};
|
||||
const resolvedProps: Record<string, string> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(props)) {
|
||||
if (value !== undefined && value !== null) {
|
||||
const resolvedValue = resolveResponsiveValue(value, breakpoint);
|
||||
if (resolvedValue !== undefined) {
|
||||
resolvedProps[key] = resolvedValue;
|
||||
dataAttributes[`data-${key}`] = resolvedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
classNames,
|
||||
dataAttributes,
|
||||
resolvedProps, // Also return resolved props for convenience
|
||||
};
|
||||
}
|
||||
@@ -58,3 +58,6 @@ export * from './props';
|
||||
|
||||
// Hooks
|
||||
export { useBreakpoint } from './hooks/useBreakpoint';
|
||||
|
||||
// Component Definitions
|
||||
export * from './utils/componentDefinitions';
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { componentDefinitions } from './utils/componentDefinitions';
|
||||
|
||||
/** @public */
|
||||
export type AsProps =
|
||||
| 'div'
|
||||
@@ -131,3 +133,43 @@ export interface UtilityProps extends SpaceProps {
|
||||
justifyContent?: Responsive<JustifyContent>;
|
||||
rowSpan?: Responsive<Columns | 'full'>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base type for the component styles structure
|
||||
* @public
|
||||
*/
|
||||
export type ClassNamesMap = Record<string, string>;
|
||||
|
||||
/**
|
||||
* Base type for the component styles structure
|
||||
* @public
|
||||
*/
|
||||
export type DataAttributeValues = readonly (string | number | boolean)[];
|
||||
|
||||
/**
|
||||
* Base type for the component styles structure
|
||||
* @public
|
||||
*/
|
||||
export type DataAttributesMap = Record<string, DataAttributeValues>;
|
||||
|
||||
/**
|
||||
* Base type for the component styles structure
|
||||
* @public
|
||||
*/
|
||||
export interface ComponentDefinition {
|
||||
classNames: ClassNamesMap;
|
||||
dataAttributes?: DataAttributesMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type utilities for extracting information from the component styles
|
||||
* @public
|
||||
*/
|
||||
export type ComponentDefinitionName = keyof typeof componentDefinitions;
|
||||
|
||||
/**
|
||||
* Helper type to extract class names for a component
|
||||
* @public
|
||||
*/
|
||||
export type ComponentClassNames<T extends ComponentDefinitionName> =
|
||||
(typeof componentDefinitions)[T]['classNames'];
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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 { ComponentDefinition } from '../types';
|
||||
|
||||
/**
|
||||
* Component definitions for the Canon library
|
||||
* @public
|
||||
*/
|
||||
export const componentDefinitions = {
|
||||
Avatar: {
|
||||
classNames: {
|
||||
root: 'canon-AvatarRoot',
|
||||
image: 'canon-AvatarImage',
|
||||
fallback: 'canon-AvatarFallback',
|
||||
},
|
||||
dataAttributes: {
|
||||
size: ['small', 'medium', 'large'] as const,
|
||||
},
|
||||
},
|
||||
Box: {
|
||||
classNames: {
|
||||
root: 'canon-Box',
|
||||
},
|
||||
},
|
||||
Button: {
|
||||
classNames: {
|
||||
root: 'canon-Button',
|
||||
},
|
||||
dataAttributes: {
|
||||
size: ['small', 'medium', 'large'] as const,
|
||||
variant: ['primary', 'secondary', 'ghost'] as const,
|
||||
},
|
||||
},
|
||||
ButtonIcon: {
|
||||
classNames: {
|
||||
root: 'canon-ButtonIcon',
|
||||
},
|
||||
},
|
||||
ButtonLink: {
|
||||
classNames: {
|
||||
root: 'canon-ButtonLink',
|
||||
},
|
||||
},
|
||||
Checkbox: {
|
||||
classNames: {
|
||||
root: 'canon-CheckboxRoot',
|
||||
label: 'canon-CheckboxLabel',
|
||||
indicator: 'canon-CheckboxIndicator',
|
||||
},
|
||||
dataAttributes: {
|
||||
checked: [true, false] as const,
|
||||
},
|
||||
},
|
||||
Collapsible: {
|
||||
classNames: {
|
||||
root: 'canon-CollapsibleRoot',
|
||||
trigger: 'canon-CollapsibleTrigger',
|
||||
panel: 'canon-CollapsiblePanel',
|
||||
},
|
||||
},
|
||||
Container: {
|
||||
classNames: {
|
||||
root: 'canon-Container',
|
||||
},
|
||||
},
|
||||
FieldLabel: {
|
||||
classNames: {
|
||||
root: 'canon-FieldLabel',
|
||||
label: 'canon-FieldLabelLabel',
|
||||
secondaryLabel: 'canon-FieldLabelSecondaryLabel',
|
||||
description: 'canon-FieldLabelDescription',
|
||||
},
|
||||
},
|
||||
Flex: {
|
||||
classNames: {
|
||||
root: 'canon-Flex',
|
||||
},
|
||||
},
|
||||
Grid: {
|
||||
classNames: {
|
||||
root: 'canon-Grid',
|
||||
item: 'canon-GridItem',
|
||||
},
|
||||
},
|
||||
Heading: {
|
||||
classNames: {
|
||||
root: 'canon-Heading',
|
||||
},
|
||||
dataAttributes: {
|
||||
variant: ['title1', 'title2', 'title3', 'subtitle'] as const,
|
||||
color: ['primary', 'secondary', 'muted'] as const,
|
||||
truncate: [true, false] as const,
|
||||
},
|
||||
},
|
||||
Icon: {
|
||||
classNames: {
|
||||
root: 'canon-Icon',
|
||||
},
|
||||
},
|
||||
Link: {
|
||||
classNames: {
|
||||
root: 'canon-Link',
|
||||
},
|
||||
dataAttributes: {
|
||||
variant: ['subtitle', 'body', 'caption', 'label'] as const,
|
||||
weight: ['regular', 'bold'] as const,
|
||||
},
|
||||
},
|
||||
Menu: {
|
||||
classNames: {
|
||||
trigger: 'canon-MenuTrigger',
|
||||
backdrop: 'canon-MenuBackdrop',
|
||||
positioner: 'canon-MenuPositioner',
|
||||
popup: 'canon-MenuPopup',
|
||||
arrow: 'canon-MenuArrow',
|
||||
item: 'canon-MenuItem',
|
||||
group: 'canon-MenuGroup',
|
||||
groupLabel: 'canon-MenuGroupLabel',
|
||||
radioGroup: 'canon-MenuRadioGroup',
|
||||
radioItem: 'canon-MenuRadioItem',
|
||||
radioItemIndicator: 'canon-MenuRadioItemIndicator',
|
||||
checkboxItem: 'canon-MenuCheckboxItem',
|
||||
checkboxItemIndicator: 'canon-MenuCheckboxItemIndicator',
|
||||
submenuTrigger: 'canon-MenuSubmenuTrigger',
|
||||
separator: 'canon-MenuSeparator',
|
||||
},
|
||||
},
|
||||
RadioGroup: {
|
||||
classNames: {
|
||||
root: 'canon-RadioGroup',
|
||||
content: 'canon-RadioGroupContent',
|
||||
radio: 'canon-Radio',
|
||||
},
|
||||
},
|
||||
ScrollArea: {
|
||||
classNames: {
|
||||
root: 'canon-ScrollAreaRoot',
|
||||
viewport: 'canon-ScrollAreaViewport',
|
||||
scrollbar: 'canon-ScrollAreaScrollbar',
|
||||
thumb: 'canon-ScrollAreaThumb',
|
||||
},
|
||||
},
|
||||
Select: {
|
||||
classNames: {
|
||||
root: 'canon-Select',
|
||||
required: 'canon-SelectRequired',
|
||||
trigger: 'canon-SelectTrigger',
|
||||
value: 'canon-SelectValue',
|
||||
icon: 'canon-SelectIcon',
|
||||
popup: 'canon-SelectPopup',
|
||||
item: 'canon-SelectItem',
|
||||
itemIndicator: 'canon-SelectItemIndicator',
|
||||
itemText: 'canon-SelectItemText',
|
||||
description: 'canon-SelectDescription',
|
||||
error: 'canon-SelectError',
|
||||
},
|
||||
dataAttributes: {
|
||||
size: ['small', 'medium'] as const,
|
||||
},
|
||||
},
|
||||
Switch: {
|
||||
classNames: {
|
||||
root: 'canon-Switch',
|
||||
indicator: 'canon-SwitchIndicator',
|
||||
},
|
||||
},
|
||||
Table: {
|
||||
classNames: {
|
||||
root: 'canon-TableRoot',
|
||||
header: 'canon-TableHeader',
|
||||
body: 'canon-TableBody',
|
||||
row: 'canon-TableRow',
|
||||
head: 'canon-TableHead',
|
||||
caption: 'canon-TableCaption',
|
||||
cell: 'canon-TableCell',
|
||||
cellText: 'canon-TableCellText',
|
||||
cellLink: 'canon-TableCellLink',
|
||||
cellProfile: 'canon-TableCellProfile',
|
||||
cellProfileAvatar: 'canon-TableCellProfileAvatar',
|
||||
cellProfileAvatarImage: 'canon-TableCellProfileAvatarImage',
|
||||
cellProfileAvatarFallback: 'canon-TableCellProfileAvatarFallback',
|
||||
cellProfileName: 'canon-TableCellProfileName',
|
||||
cellProfileLink: 'canon-TableCellProfileLink',
|
||||
},
|
||||
},
|
||||
Tabs: {
|
||||
classNames: {
|
||||
root: 'canon-TabsRoot',
|
||||
list: 'canon-TabsList',
|
||||
indicator: 'canon-TabsIndicator',
|
||||
tab: 'canon-TabsTab',
|
||||
panel: 'canon-TabsPanel',
|
||||
},
|
||||
},
|
||||
Text: {
|
||||
classNames: {
|
||||
root: 'canon-Text',
|
||||
},
|
||||
dataAttributes: {
|
||||
variant: ['subtitle', 'body', 'caption', 'label'] as const,
|
||||
weight: ['regular', 'bold'] as const,
|
||||
color: ['primary', 'secondary', 'danger', 'warning', 'success'] as const,
|
||||
truncate: [true, false] as const,
|
||||
},
|
||||
},
|
||||
TextField: {
|
||||
classNames: {
|
||||
root: 'canon-TextField',
|
||||
inputWrapper: 'canon-TextFieldInputWrapper',
|
||||
icon: 'canon-TextFieldIcon',
|
||||
input: 'canon-TextFieldInput',
|
||||
},
|
||||
dataAttributes: {
|
||||
invalid: [true, false] as const,
|
||||
disabled: [true, false] as const,
|
||||
},
|
||||
},
|
||||
Tooltip: {
|
||||
classNames: {
|
||||
trigger: 'canon-TooltipTrigger',
|
||||
positioner: 'canon-TooltipPositioner',
|
||||
popup: 'canon-TooltipPopup',
|
||||
arrow: 'canon-TooltipArrow',
|
||||
},
|
||||
},
|
||||
} as const satisfies Record<string, ComponentDefinition>;
|
||||
Reference in New Issue
Block a user