diff --git a/packages/javascript/doodle-ui/src/components/Accordion/Accordion.styles.ts b/packages/javascript/doodle-ui/src/components/Accordion/Accordion.styles.ts new file mode 100644 index 000000000000..dc69106e4fc9 --- /dev/null +++ b/packages/javascript/doodle-ui/src/components/Accordion/Accordion.styles.ts @@ -0,0 +1,31 @@ +// Copyright 2026 Specter Ops, Inc. +// +// Licensed under the Apache License, Version 2.0 +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +import { cn } from '../utils'; + +export const accordionItemClasses = 'bg-[color:var(--accordion-fill)] rounded-lg mb-4'; + +export const accordionHeaderClasses = cn( + 'flex flex-1 gap-1 items-center rounded-md text-main font-bold transition-all', + 'hover:underline', + 'focus:outline-none', + 'focus-visible:focus-ring focus-visible:underline', + '[&[data-state=open]>svg]:rotate-180', + 'p-4' +); + +export const accordionContentClasses = + 'overflow-hidden text-sm text-main transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down'; diff --git a/packages/javascript/doodle-ui/src/components/Accordion/Accordion.tsx b/packages/javascript/doodle-ui/src/components/Accordion/Accordion.tsx index 831826e4cdba..e596aa1a5712 100644 --- a/packages/javascript/doodle-ui/src/components/Accordion/Accordion.tsx +++ b/packages/javascript/doodle-ui/src/components/Accordion/Accordion.tsx @@ -13,19 +13,19 @@ // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 + import * as AccordionPrimitive from '@radix-ui/react-accordion'; import * as React from 'react'; import { cn } from '../utils'; +import { accordionContentClasses, accordionHeaderClasses, accordionItemClasses } from './Accordion.styles'; const Accordion = AccordionPrimitive.Root; const AccordionItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ ...props }, ref) => ( - -)); +>(({ ...props }, ref) => ); AccordionItem.displayName = 'AccordionItem'; const AccordionHeader = React.forwardRef< @@ -33,13 +33,7 @@ const AccordionHeader = React.forwardRef< React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - svg]:rotate-180 p-4', - className - )} - {...props}> + {children} @@ -50,10 +44,7 @@ const AccordionContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - +
{children}
)); diff --git a/packages/javascript/doodle-ui/src/components/Alert/Alert.styles.ts b/packages/javascript/doodle-ui/src/components/Alert/Alert.styles.ts new file mode 100644 index 000000000000..10118ebc3b07 --- /dev/null +++ b/packages/javascript/doodle-ui/src/components/Alert/Alert.styles.ts @@ -0,0 +1,44 @@ +// Copyright 2026 Specter Ops, Inc. +// +// Licensed under the Apache License, Version 2.0 +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +import { cva } from 'class-variance-authority'; + +export const alertVariants = cva('flex text-sm w-full rounded px-4 py-2 ', { + variants: { + variant: { + // TODO: Update in https://specterops.atlassian.net/browse/BED-8069 + // default: 'bg-status-indeterminate-fill text-contrast', + default: 'bg-status-indeterminate-fill text-neutral-1', + error: 'bg-status-error-fill text-status-error-text [&>div>svg]:text-status-error-main', + info: 'bg-status-info-fill text-status-info-text [&>div>svg]:text-status-info-main', + success: 'bg-status-success-fill text-status-success-text [&>div>svg]:text-status-success-main', + warning: 'bg-status-warning-fill text-status-warning-text [&>div>svg]:text-status-warning-main', + }, + }, + defaultVariants: { + variant: 'default', + }, +}); + +export const alertBodyClasses = 'flex flex-col justify-center flex-grow py-2 gap-1'; + +export const alertTitleClasses = 'text-base/6 font-medium tracking-tight'; + +export const alertActionClasses = + 'h-6 rounded-sm px-1 font-medium uppercase focus:outline-none focus-visible:focus-ring'; + +export const alertDismissClasses = + 'ml-2 inline-flex h-6 items-center justify-center rounded-sm px-1 focus:outline-none focus-visible:focus-ring'; diff --git a/packages/javascript/doodle-ui/src/components/Alert/Alert.tsx b/packages/javascript/doodle-ui/src/components/Alert/Alert.tsx index 8ce6690e9a24..600ff577d0e4 100644 --- a/packages/javascript/doodle-ui/src/components/Alert/Alert.tsx +++ b/packages/javascript/doodle-ui/src/components/Alert/Alert.tsx @@ -16,27 +16,17 @@ import { faClose } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { cva, type VariantProps } from 'class-variance-authority'; +import { type VariantProps } from 'class-variance-authority'; import { forwardRef, HTMLAttributes, ReactNode } from 'react'; import { AppIcon } from '../../styleguide/components/AppIcons/AppIcons'; import { cn } from '../utils'; - -const alertVariants = cva('flex text-sm w-full rounded px-4 py-2 ', { - variants: { - variant: { - // TODO: Update in https://specterops.atlassian.net/browse/BED-8069 - // default: 'bg-status-indeterminate-fill text-contrast', - default: 'bg-status-indeterminate-fill text-neutral-1', - error: 'bg-status-error-fill text-status-error-text [&>div>svg]:text-status-error-main', - info: 'bg-status-info-fill text-status-info-text [&>div>svg]:text-status-info-main', - success: 'bg-status-success-fill text-status-success-text [&>div>svg]:text-status-success-main', - warning: 'bg-status-warning-fill text-status-warning-text [&>div>svg]:text-status-warning-main', - }, - }, - defaultVariants: { - variant: 'default', - }, -}); +import { + alertActionClasses, + alertBodyClasses, + alertDismissClasses, + alertTitleClasses, + alertVariants, +} from './Alert.styles'; const iconMap = { default: , @@ -59,28 +49,20 @@ const Alert = forwardRef<
{iconMap[variant ?? 'default']}
-
- {title &&
{title}
} +
+ {title &&
{title}
} {children}
{action && ( - )} {onClose && ( - )} diff --git a/packages/javascript/doodle-ui/src/components/Badge/Badge.styles.ts b/packages/javascript/doodle-ui/src/components/Badge/Badge.styles.ts index 28e6a46bfd89..feef89552edc 100644 --- a/packages/javascript/doodle-ui/src/components/Badge/Badge.styles.ts +++ b/packages/javascript/doodle-ui/src/components/Badge/Badge.styles.ts @@ -14,21 +14,22 @@ // // SPDX-License-Identifier: Apache-2.0 import { cva } from 'class-variance-authority'; +import { cn } from '../utils'; -const badgeBaseClasses = [ +const badgeBaseClasses = cn( 'inline-flex min-w-16 items-center justify-center', 'rounded px-2 py-1', - 'text-base text-main', -]; + 'text-base text-main' +); export const BadgeVariants = cva(badgeBaseClasses, { variants: { variant: { fill: 'bg-[color:var(--badge-surface)]', - outline: [ + outline: cn( 'border border-[color:var(--badge-accent)] bg-[color:var(--badge-grey-surface)]', - '[&>span>svg]:text-[color:var(--badge-accent)]', - ], + '[&>span>svg]:text-[color:var(--badge-accent)]' + ), }, color: { primary: '[--badge-surface:var(--badge-primary-surface)] [--badge-accent:var(--badge-primary-accent)]', @@ -60,6 +61,6 @@ export const BadgeVariants = cva(badgeBaseClasses, { }, }); -export const badgeIconClasses = ['badge-icon flex shrink-0 items-center', '[&>svg]:h-3 [&>svg]:w-3']; +export const badgeIconClasses = cn('badge-icon flex shrink-0 items-center', '[&>svg]:h-3 [&>svg]:w-3'); export const badgeLabelClasses = 'badge-label translate-y-[1px]'; diff --git a/packages/javascript/doodle-ui/src/components/Button/Button.styles.ts b/packages/javascript/doodle-ui/src/components/Button/Button.styles.ts index 0911344971f4..3a95e6b89a56 100644 --- a/packages/javascript/doodle-ui/src/components/Button/Button.styles.ts +++ b/packages/javascript/doodle-ui/src/components/Button/Button.styles.ts @@ -16,38 +16,38 @@ import { cva } from 'class-variance-authority'; import { cn } from '../utils'; -export const buttonBaseClasses = [ +export const buttonBaseClasses = cn( 'inline-flex items-center justify-center whitespace-nowrap transition-colors', 'focus:outline-none focus-visible:focus-ring', 'disabled:text-[color:var(--button-disabled-text)] disabled:pointer-events-none', - 'has-[svg]:gap-2 [&>svg]:shrink-0', -]; + 'has-[svg]:gap-2 [&>svg]:shrink-0' +); const containedButtonGeometryClasses = 'rounded p-2 text-sm/none'; -const containedButtonStateClasses = [ +const containedButtonStateClasses = cn( 'hover:bg-secondary hover:text-inverse', 'focus-visible:bg-secondary focus-visible:text-inverse', - 'active:bg-primary-variant active:text-inverse', -]; + 'active:bg-primary-variant active:text-inverse' +); -const containedPrimaryClasses = [ +const containedPrimaryClasses = cn( 'border border-transparent bg-primary text-inverse', - ...containedButtonStateClasses, - 'disabled:bg-[color:var(--button-disabled-fill)]', -]; + containedButtonStateClasses, + 'disabled:bg-[color:var(--button-disabled-fill)]' +); -const containedSecondaryClasses = [ +const containedSecondaryClasses = cn( 'border border-[color:var(--button-secondary-border)] bg-elevation-1 text-main', - ...containedButtonStateClasses, - 'disabled:bg-[color:var(--button-disabled-fill)]', -]; + containedButtonStateClasses, + 'disabled:bg-[color:var(--button-disabled-fill)]' +); -const containedTertiaryClasses = [ +const containedTertiaryClasses = cn( 'border border-brand-orange bg-elevation-1 text-main', - ...containedButtonStateClasses, - 'disabled:border-[color:var(--button-disabled-fill)] disabled:bg-[color:var(--button-disabled-fill)]', -]; + containedButtonStateClasses, + 'disabled:border-[color:var(--button-disabled-fill)] disabled:bg-[color:var(--button-disabled-fill)]' +); export const ButtonVariants = cva(buttonBaseClasses, { variants: { @@ -60,20 +60,20 @@ export const ButtonVariants = cva(buttonBaseClasses, { /** * @deprecated Use TextButton instead. */ - transparent: [ + transparent: cn( 'rounded-3xl border border-[color:var(--button-transparent-border)] bg-transparent text-main', 'hover:border-secondary hover:bg-secondary hover:text-[color:var(--button-highlight-text)] hover:no-underline', - 'focus-visible:border-primary focus-visible:bg-secondary focus-visible:text-[color:var(--button-highlight-text)]', - ], + 'focus-visible:border-primary focus-visible:bg-secondary focus-visible:text-[color:var(--button-highlight-text)]' + ), // TODO - legacy, remove in BED-7635 /** * @deprecated Use IconButton instead. */ - icon: [ + icon: cn( 'rounded-full bg-[color:var(--button-icon-fill)] text-common-dark shadow-outer-1 has-[svg]:p-2', 'hover:border-2 hover:border-primary', - 'active:border-none', - ], + 'active:border-none' + ), }, // TODO - remove as the only usage of this is with variant="text" /** @@ -123,7 +123,7 @@ export const ButtonVariants = cva(buttonBaseClasses, { }); export const TextButtonBaseClasses = cn( - ...buttonBaseClasses, + buttonBaseClasses, 'rounded-3xl px-2 py-1 has-[svg]:px-1', 'active:text-[color:var(--button-text-active)]', 'hover:text-secondary', diff --git a/packages/javascript/doodle-ui/src/components/Card/Card.styles.ts b/packages/javascript/doodle-ui/src/components/Card/Card.styles.ts new file mode 100644 index 000000000000..02c422b196ed --- /dev/null +++ b/packages/javascript/doodle-ui/src/components/Card/Card.styles.ts @@ -0,0 +1,23 @@ +// Copyright 2026 Specter Ops, Inc. +// +// Licensed under the Apache License, Version 2.0 +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +export const cardClasses = 'rounded-lg text-main bg-neutral-1 border border-solid border-[color:var(--card-border)]'; + +export const cardHeaderClasses = 'flex flex-col space-y-1.5 p-3 pt-0 first:pt-3'; + +export const cardContentClasses = 'p-3 pt-0 first:pt-3'; + +export const cardFooterClasses = 'flex items-center p-3 pt-0 first:pt-3'; diff --git a/packages/javascript/doodle-ui/src/components/Card/Card.tsx b/packages/javascript/doodle-ui/src/components/Card/Card.tsx index 74c0d47761dd..9fe1432c9a9b 100644 --- a/packages/javascript/doodle-ui/src/components/Card/Card.tsx +++ b/packages/javascript/doodle-ui/src/components/Card/Card.tsx @@ -13,26 +13,19 @@ // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 + import * as React from 'react'; import { Typography } from '../Typography'; import { cn } from '../utils'; +import { cardClasses, cardContentClasses, cardFooterClasses, cardHeaderClasses } from './Card.styles'; const Card = React.forwardRef>(({ className, ...props }, ref) => ( -
+
)); Card.displayName = 'Card'; const CardHeader = React.forwardRef>( - ({ className, ...props }, ref) => ( -
- ) + ({ className, ...props }, ref) =>
); CardHeader.displayName = 'CardHeader'; @@ -49,14 +42,12 @@ const CardDescription = React.forwardRef>( - ({ className, ...props }, ref) =>
+ ({ className, ...props }, ref) =>
); CardContent.displayName = 'CardContent'; const CardFooter = React.forwardRef>( - ({ className, ...props }, ref) => ( -
- ) + ({ className, ...props }, ref) =>
); CardFooter.displayName = 'CardFooter'; diff --git a/packages/javascript/doodle-ui/src/components/Checkbox/Checkbox.styles.ts b/packages/javascript/doodle-ui/src/components/Checkbox/Checkbox.styles.ts index 4e3d59f72c05..b3375ec636b7 100644 --- a/packages/javascript/doodle-ui/src/components/Checkbox/Checkbox.styles.ts +++ b/packages/javascript/doodle-ui/src/components/Checkbox/Checkbox.styles.ts @@ -14,9 +14,10 @@ // // SPDX-License-Identifier: Apache-2.0 import { cva } from 'class-variance-authority'; +import { cn } from '../utils'; export const CheckboxVariants = cva( - [ + cn( 'peer shrink-0 rounded-sm border border-[color:var(--checkbox-border)] ring-offset-background', 'enabled:hover:border-[color:var(--checkbox-hover)] enabled:active:border-primary-variant', 'focus:outline-none', @@ -29,8 +30,8 @@ export const CheckboxVariants = cva( 'enabled:active:data-[state=checked]:border-[color:var(--checkbox-checked-active-border)] enabled:active:data-[state=indeterminate]:border-[color:var(--checkbox-checked-active-border)]', 'enabled:hover:active:data-[state=checked]:border-[color:var(--checkbox-hover)] enabled:hover:active:data-[state=indeterminate]:border-[color:var(--checkbox-hover)]', 'disabled:hover:data-[state=checked]:bg-[color:var(--checkbox-disabled-checked-hover-fill)]', - 'enabled:aria-[invalid=true]:data-[state=unchecked]:border-status-error-main', - ], + 'enabled:aria-[invalid=true]:data-[state=unchecked]:border-status-error-main' + ), { variants: { size: { diff --git a/packages/javascript/doodle-ui/src/components/IconButton/IconButton.styles.ts b/packages/javascript/doodle-ui/src/components/IconButton/IconButton.styles.ts index 1610b8d84a1b..4cdce9a770ee 100644 --- a/packages/javascript/doodle-ui/src/components/IconButton/IconButton.styles.ts +++ b/packages/javascript/doodle-ui/src/components/IconButton/IconButton.styles.ts @@ -15,35 +15,36 @@ // SPDX-License-Identifier: Apache-2.0 import { cva } from 'class-variance-authority'; import { buttonBaseClasses } from '../Button/Button.styles'; +import { cn } from '../utils'; -const defaultIconButtonClasses = [ +export const defaultIconButtonClasses = cn( 'hover:text-primary', 'active:bg-transparent active:text-secondary', - 'focus-visible:ring-transparent focus-visible:ring-offset-0 focus-visible:ring-offset-transparent focus-visible:text-primary', -]; + 'focus-visible:ring-transparent focus-visible:ring-offset-0 focus-visible:ring-offset-transparent focus-visible:text-primary' +); -export const iconPrimaryClasses = [ +export const iconPrimaryClasses = cn( 'bg-primary text-[color:var(--button-primary-text)] shadow-outer-1', 'hover:bg-secondary', 'focus-visible:bg-secondary', 'active:bg-[color:var(--button-primary-active-fill)]', - 'disabled:shadow-none disabled:bg-[color:var(--button-disabled-fill)]', -]; + 'disabled:shadow-none disabled:bg-[color:var(--button-disabled-fill)]' +); -export const iconSecondaryClasses = [ +export const iconSecondaryClasses = cn( 'bg-[color:var(--button-secondary-fill)] text-[color:var(--button-secondary-text)] shadow-outer-1', 'hover:bg-secondary hover:text-[color:var(--button-highlight-text)]', 'focus-visible:bg-secondary focus-visible:text-[color:var(--button-highlight-text)]', 'active:bg-[color:var(--button-secondary-active-fill)] active:text-[color:var(--button-secondary-text)]', - 'disabled:bg-[color:var(--button-disabled-fill)] disabled:shadow-none', -]; + 'disabled:bg-[color:var(--button-disabled-fill)] disabled:shadow-none' +); export const IconButtonVariants = cva( - [ - ...buttonBaseClasses, + cn( + buttonBaseClasses, 'inline-grid h-fit aspect-square box-border', - 'shrink-0 place-items-center align-middle rounded-full border-0 p-2', - ], + 'shrink-0 place-items-center align-middle rounded-full border-0 p-2' + ), { variants: { variant: { @@ -57,3 +58,6 @@ export const IconButtonVariants = cva( }, } ); + +export const iconButtonIconClasses = + 'inline-flex size-[var(--icon-button-icon-size)] shrink-0 items-center justify-center [&>*]:size-full [&_svg]:size-full'; diff --git a/packages/javascript/doodle-ui/src/components/IconButton/IconButton.test.tsx b/packages/javascript/doodle-ui/src/components/IconButton/IconButton.test.tsx index d567f5869327..1a74d77484a8 100644 --- a/packages/javascript/doodle-ui/src/components/IconButton/IconButton.test.tsx +++ b/packages/javascript/doodle-ui/src/components/IconButton/IconButton.test.tsx @@ -190,7 +190,7 @@ describe('IconButton', () => { ); const button = screen.getByRole('button', { name: `${variant} action` }); - const expectedClasses = variantClasses.flatMap((classNames) => classNames.split(' ')); + const expectedClasses = variantClasses.split(' '); expect(expectedClasses.every((className) => button.classList.contains(className))).toBe(true); }); diff --git a/packages/javascript/doodle-ui/src/components/IconButton/IconButton.tsx b/packages/javascript/doodle-ui/src/components/IconButton/IconButton.tsx index d8760d459b70..af0cad253604 100644 --- a/packages/javascript/doodle-ui/src/components/IconButton/IconButton.tsx +++ b/packages/javascript/doodle-ui/src/components/IconButton/IconButton.tsx @@ -19,8 +19,7 @@ import * as React from 'react'; import { AccessibleIcon } from '../AccessibleIcon'; import { Tooltip, type TooltipPosition } from '../Tooltip'; import { cn, cnWithState } from '../utils'; -import { IconButtonVariants } from './IconButton.styles'; - +import { iconButtonIconClasses, IconButtonVariants } from './IconButton.styles'; export { IconButtonVariants } from './IconButton.styles'; export interface IconButtonProps extends Omit { @@ -74,9 +73,7 @@ export const IconButton = React.forwardRef(f '--icon-button-icon-size': `${size}px`, }) as IconButtonStyle }> - - {buttonIcon} - + {buttonIcon} ); diff --git a/packages/javascript/doodle-ui/src/components/Input/Input.styles.ts b/packages/javascript/doodle-ui/src/components/Input/Input.styles.ts index 1dce32d128d4..4a7f3fe7060d 100644 --- a/packages/javascript/doodle-ui/src/components/Input/Input.styles.ts +++ b/packages/javascript/doodle-ui/src/components/Input/Input.styles.ts @@ -14,36 +14,38 @@ // // SPDX-License-Identifier: Apache-2.0 import { cva } from 'class-variance-authority'; +import { invalidControlClasses } from '../formControl.styles'; +import { cn } from '../utils'; -const inputBaseClasses = [ +const inputBaseClasses = cn( 'flex h-10 w-full', 'text-base text-main placeholder:text-[color:var(--input-placeholder-text)]', - 'disabled:cursor-not-allowed disabled:opacity-50', - 'file:cursor-pointer file:border-0 file:bg-transparent file:pr-3 file:text-sm file:font-medium file:text-main', -]; + 'disabled:cursor-not-allowed disabled:opacity-50 disabled:border-[color:var(--input-border-disabled)]', + invalidControlClasses, + 'file:cursor-pointer file:border-0 file:bg-transparent file:pr-3 file:text-sm file:font-medium file:text-main' +); export const InputVariants = cva(inputBaseClasses, { variants: { variant: { - outlined: [ + outlined: cn( 'rounded-md border border-[color:var(--input-outlined-border-default)] bg-[color:var(--input-fill)] px-3 py-2 text-sm', 'enabled:hover:border-[color:var(--input-outlined-border-hover)]', 'focus:outline-none focus:focus-ring focus:border-[color:var(--input-outlined-border-default)] enabled:hover:focus:border-[color:var(--input-outlined-hover-focus-border)]', - 'disabled:border-[color:var(--input-border-disabled)] disabled:bg-[color:var(--input-disabled-fill)] disabled:text-disabled disabled:placeholder:text-disabled disabled:opacity-100', - 'enabled:aria-[invalid=true]:border-status-error-main enabled:aria-[invalid=true]:hover:border-status-error-main enabled:aria-[invalid=true]:focus:border-status-error-main aria-[invalid=true]:enabled:hover:focus:border-status-error-main disabled:aria-[invalid=true]:border-[color:var(--input-disabled-invalid-border)]', - ], - underlined: [ + 'disabled:bg-[color:var(--input-disabled-fill)] disabled:text-disabled disabled:placeholder:text-disabled disabled:opacity-100' + ), + underlined: cn( 'rounded-sm border-b border-b-[color:var(--input-border-default)] bg-transparent', 'hover:border-b-2', - 'focus:border-b-2 focus:border-[color:var(--input-border-focus)] focus:outline-none focus:focus-ring', - ], + 'focus:border-b-2 focus:border-[color:var(--input-border-focus)] focus:outline-none focus:focus-ring' + ), }, intent: { - time: [ + time: cn( 'appearance-none', '[&::-webkit-calendar-picker-indicator]:hidden', - '[&::-webkit-calendar-picker-indicator]:appearance-none', - ], + '[&::-webkit-calendar-picker-indicator]:appearance-none' + ), }, }, defaultVariants: { diff --git a/packages/javascript/doodle-ui/src/components/Label/Label.styles.ts b/packages/javascript/doodle-ui/src/components/Label/Label.styles.ts new file mode 100644 index 000000000000..3b1c772d1a34 --- /dev/null +++ b/packages/javascript/doodle-ui/src/components/Label/Label.styles.ts @@ -0,0 +1,30 @@ +// Copyright 2026 Specter Ops, Inc. +// +// Licensed under the Apache License, Version 2.0 +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +import { cva } from 'class-variance-authority'; + +export const LabelVariants = cva('leading-none peer-disabled:cursor-not-allowed peer-disabled:text-disabled', { + variants: { + size: { + small: 'text-sm font-medium', + medium: 'text-base font-bold', + large: 'text-lg font-bold', + }, + }, + defaultVariants: { + size: 'medium', + }, +}); diff --git a/packages/javascript/doodle-ui/src/components/Label/Label.tsx b/packages/javascript/doodle-ui/src/components/Label/Label.tsx index 5d82ac600ce6..fd104679aa92 100644 --- a/packages/javascript/doodle-ui/src/components/Label/Label.tsx +++ b/packages/javascript/doodle-ui/src/components/Label/Label.tsx @@ -13,23 +13,12 @@ // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 + import * as LabelPrimitive from '@radix-ui/react-label'; -import { cva, type VariantProps } from 'class-variance-authority'; +import { type VariantProps } from 'class-variance-authority'; import * as React from 'react'; import { cn } from '../utils'; - -const LabelVariants = cva('leading-none peer-disabled:cursor-not-allowed peer-disabled:text-disabled', { - variants: { - size: { - small: 'text-sm font-medium', - medium: 'text-base font-bold', - large: 'text-lg font-bold', - }, - }, - defaultVariants: { - size: 'medium', - }, -}); +import { LabelVariants } from './Label.styles'; const Label = React.forwardRef< React.ElementRef, diff --git a/packages/javascript/doodle-ui/src/components/Link/Link.styles.ts b/packages/javascript/doodle-ui/src/components/Link/Link.styles.ts new file mode 100644 index 000000000000..74589b76de6f --- /dev/null +++ b/packages/javascript/doodle-ui/src/components/Link/Link.styles.ts @@ -0,0 +1,39 @@ +// Copyright 2026 Specter Ops, Inc. +// +// Licensed under the Apache License, Version 2.0 +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +import { cva } from 'class-variance-authority'; +import { cn } from '../utils'; + +export const styledLinkClasses = cn( + 'text-link underline underline-offset-1 decoration-secondary', + 'hover:text-link-hover hover:decoration-link', + 'focus-visible:underline focus-visible:decoration-2 focus-visible:underline-offset-2', + 'dark:no-underline dark:hover:underline' +); + +export const linkVariants = cva('inline-flex items-center rounded-sm focus:outline-none focus-visible:focus-ring', { + variants: { + variant: { + styled: styledLinkClasses, + unstyled: 'text-inherit no-underline', + }, + }, + defaultVariants: { + variant: 'styled', + }, +}); + +export const linkExternalIconClasses = 'ml-0.5 shrink-0 text-[0.85em] align-baseline'; diff --git a/packages/javascript/doodle-ui/src/components/Link/Link.tsx b/packages/javascript/doodle-ui/src/components/Link/Link.tsx index 349247c9f620..1581f9e657d4 100644 --- a/packages/javascript/doodle-ui/src/components/Link/Link.tsx +++ b/packages/javascript/doodle-ui/src/components/Link/Link.tsx @@ -16,24 +16,10 @@ import { faExternalLink } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { cva, type VariantProps } from 'class-variance-authority'; +import { type VariantProps } from 'class-variance-authority'; import * as React from 'react'; import { cn } from '../utils'; - -const styledLinkClasses = - 'text-link underline underline-offset-1 decoration-secondary hover:text-link-hover hover:decoration-link focus-visible:underline focus-visible:decoration-2 focus-visible:underline-offset-2 dark:no-underline dark:hover:underline'; - -const linkVariants = cva('inline-flex items-center rounded-sm focus:outline-none focus-visible:focus-ring', { - variants: { - variant: { - styled: styledLinkClasses, - unstyled: 'text-inherit no-underline', - }, - }, - defaultVariants: { - variant: 'styled', - }, -}); +import { linkExternalIconClasses, linkVariants } from './Link.styles'; export type LinkProps = Omit, 'children' | 'href' | 'target' | 'rel'> & VariantProps & { @@ -53,11 +39,7 @@ export const Link = React.forwardRef( className={cn(linkVariants({ variant }), className)} {...props}> {children}{' '} -