diff --git a/packages/javascript/bh-shared-ui/src/components/ConfirmationDialog.tsx b/packages/javascript/bh-shared-ui/src/components/ConfirmationDialog.tsx index b3715634052d..2d9d7917c34a 100644 --- a/packages/javascript/bh-shared-ui/src/components/ConfirmationDialog.tsx +++ b/packages/javascript/bh-shared-ui/src/components/ConfirmationDialog.tsx @@ -64,7 +64,7 @@ const ConfirmationDialog: React.FC<{ Please input "{challengeTxt}" prior to clicking confirm. setChallengeTxtReply(e.target.value)} value={challengeTxtReply} data-testid='confirmation-dialog_challenge-text' diff --git a/packages/javascript/bh-shared-ui/src/components/DropdownSelector/DropdownSelector.tsx b/packages/javascript/bh-shared-ui/src/components/DropdownSelector/DropdownSelector.tsx index e47700fdc7fa..635d7df73f11 100644 --- a/packages/javascript/bh-shared-ui/src/components/DropdownSelector/DropdownSelector.tsx +++ b/packages/javascript/bh-shared-ui/src/components/DropdownSelector/DropdownSelector.tsx @@ -20,7 +20,7 @@ import { Button, ButtonProps, Popover, PopoverContent, Tooltip, Typography } fro import { FC, useState } from 'react'; import { cn } from '../../utils'; import DropdownTrigger from './DropdownTrigger'; -import { optionIconStyles, optionStyles, popoverContentStyles, tooltipStyles } from './constants'; +import { optionStyles, popoverContentStyles, tooltipStyles } from './constants'; import { DropdownOption } from './types'; const DropdownSelector: FC<{ @@ -75,7 +75,6 @@ const DropdownSelector: FC<{ {option.icon && ( { +const DropdownTrigger: FC<{ + open: boolean; + selectedText: JSX.Element | string; + buttonProps?: ButtonProps; + StartAdornment?: React.FC; + EndAdornment?: React.FC; + testId?: string; + variant?: ButtonProps['variant']; +}> = (props) => { return ( - +
+ +
); }; diff --git a/packages/javascript/bh-shared-ui/src/components/DropdownSelector/DropdownTriggerContents.tsx b/packages/javascript/bh-shared-ui/src/components/DropdownSelector/DropdownTriggerContents.tsx index 4c1010e070cf..5360eadf1af2 100644 --- a/packages/javascript/bh-shared-ui/src/components/DropdownSelector/DropdownTriggerContents.tsx +++ b/packages/javascript/bh-shared-ui/src/components/DropdownSelector/DropdownTriggerContents.tsx @@ -14,83 +14,70 @@ // // SPDX-License-Identifier: Apache-2.0 import { Button, ButtonProps } from 'doodle-ui'; -import { forwardRef, type FC } from 'react'; import { cn } from '../../utils'; import { AppIcon } from '../AppIcon'; -import { dropdownIconStateStyles, selectorIconStyles, triggerStyles } from './constants'; +import { triggerStyles } from './constants'; -export type DropdownTriggerContentsProps = ButtonProps & { +type DropdownTriggerContentsProps = { open: boolean; selectedText: JSX.Element | string; buttonProps?: ButtonProps; - StartAdornment?: FC; - EndAdornment?: FC; + StartAdornment?: React.FC; + EndAdornment?: React.FC; testId?: string; variant?: ButtonProps['variant']; readOnly?: boolean; }; -const DropdownTriggerContents = forwardRef( - ( - { - open, - selectedText, - buttonProps, - StartAdornment, - EndAdornment, - testId, - variant, - readOnly, - className, - ...props - }, - ref - ) => { - const buttonPrimary = variant === 'primary'; +const DropdownTriggerContents = ({ + open, + selectedText, + buttonProps, + StartAdornment, + EndAdornment, + testId, + variant, + readOnly, +}: DropdownTriggerContentsProps) => { + const buttonPrimary = variant === 'primary'; - return ( - - ); - } -); -DropdownTriggerContents.displayName = 'DropdownTriggerContents'; + + + ); +}; export default DropdownTriggerContents; diff --git a/packages/javascript/bh-shared-ui/src/components/DropdownSelector/constants.ts b/packages/javascript/bh-shared-ui/src/components/DropdownSelector/constants.ts index 4e9447153689..139bf0e078ed 100644 --- a/packages/javascript/bh-shared-ui/src/components/DropdownSelector/constants.ts +++ b/packages/javascript/bh-shared-ui/src/components/DropdownSelector/constants.ts @@ -13,21 +13,12 @@ // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 -export const focusedControlStateStyles = - 'focus:bg-primary focus:text-white dark:focus:text-neutral-dark-1 focus-visible:bg-primary focus-visible:text-white dark:focus-visible:text-neutral-dark-1'; - -export const dropdownIconStateStyles = - 'hover:[&_svg]:text-white dark:hover:[&_svg]:text-neutral-dark-1 hover:[&_svg]:fill-current hover:[&_svg_*]:text-white dark:hover:[&_svg_*]:text-neutral-dark-1 hover:[&_svg_*]:fill-current focus:[&_svg]:text-white dark:focus:[&_svg]:text-neutral-dark-1 focus:[&_svg]:fill-current focus:[&_svg_*]:text-white dark:focus:[&_svg_*]:text-neutral-dark-1 focus:[&_svg_*]:fill-current focus-visible:[&_svg]:text-white dark:focus-visible:[&_svg]:text-neutral-dark-1 focus-visible:[&_svg]:fill-current focus-visible:[&_svg_*]:text-white dark:focus-visible:[&_svg_*]:text-neutral-dark-1 focus-visible:[&_svg_*]:fill-current'; - -export const triggerStyles = `max-w-56 text-sm text-contrast rounded-md bg-transparent hover:bg-primary hover:text-white dark:hover:text-neutral-dark-1 ${focusedControlStateStyles} border shadow-outer-0 hover:border-transparent focus:border-transparent focus-visible:border-transparent border-neutral-light-5 group ${dropdownIconStateStyles}`; +export const triggerStyles = + 'max-w-56 text-sm text-contrast rounded-md bg-transparent hover:bg-primary hover:text-white border shadow-outer-0 hover:border-transparent border-neutral-light-5 group'; export const popoverContentStyles = 'flex flex-col p-0 rounded-md border border-neutral-5 bg-neutral-1'; -export const optionStyles = `px-4 py-1 rounded-none w-full justify-normal text-contrast dark:text-neutral-light-1 hover:no-underline hover:bg-neutral-4 dark:hover:text-neutral-dark-1 ${focusedControlStateStyles} ${dropdownIconStateStyles} disabled:bg-neutral-4 group`; - -export const selectorIconStyles = - 'group-hover:text-white dark:group-hover:text-neutral-dark-1 group-focus:text-white dark:group-focus:text-neutral-dark-1 group-focus-visible:text-white dark:group-focus-visible:text-neutral-dark-1'; - -export const optionIconStyles = selectorIconStyles; +export const optionStyles = + 'px-4 py-1 rounded-none w-full justify-normal hover:no-underline hover:bg-neutral-4 disabled:bg-neutral-4'; export const tooltipStyles = 'max-w-80 border-0 dark:bg-neutral-4 dark:text-white'; diff --git a/packages/javascript/bh-shared-ui/src/components/HelpTexts/AdcsEsc14ScenarioA/AdcsEsc14ScenarioA.tsx b/packages/javascript/bh-shared-ui/src/components/HelpTexts/AdcsEsc14ScenarioA/AdcsEsc14ScenarioA.tsx index 75305fa46fc4..25670344ff35 100644 --- a/packages/javascript/bh-shared-ui/src/components/HelpTexts/AdcsEsc14ScenarioA/AdcsEsc14ScenarioA.tsx +++ b/packages/javascript/bh-shared-ui/src/components/HelpTexts/AdcsEsc14ScenarioA/AdcsEsc14ScenarioA.tsx @@ -27,10 +27,15 @@ export const AltSecIdentitiesBlurb = () => ( export const AdcsEsc14ScenarioALinux: FC = () => ( <> - ADCS ESC14 Scenario A + + ADCS ESC14 Scenario A + - An attacker can add an explicit certificate mapping in the AltSecurityIdentities of the target referring to - a certificate in the attacker's possession, and then use this certificate to authenticate as the target. +

+ An attacker can add an explicit certificate mapping in the AltSecurityIdentities of the target referring + to a certificate in the attacker's possession, and then use this certificate to authenticate as the + target. +

The certificate must meet the following requirements: @@ -63,6 +68,34 @@ export const AdcsEsc14ScenarioALinux: FC = () => ( ). + + +

+ If the attacker cannot obtain a suitable certificate from the target environment, they may also be able + to use a third-party Client Authentication certificate. +

+

+ This works because explicit certificate mapping differs from implicit certificate mapping. Implicit + mapping requires the certificate to chain to a CA certificate in the domain controller's NTAuth store. + Explicit mapping does not. For explicit mapping, the certificate only needs to chain to a trusted root + CA on the domain controller. +

+

+ Windows trusts many third-party root CAs by default, so an attacker may be able to buy or steal a + third-party certificate with the Client Authentication EKU and use it for ESC14 Scenario A. For example, + providers such as{' '} + + SSL.com + {' '} + are trusted by Windows and offer client authentication certificates. +

+
+ + Execution + Obtain a certificate meeting the above requirements for example by dumping a certificate from a computer, or enrolling a new certificate as a computer: @@ -71,18 +104,20 @@ export const AdcsEsc14ScenarioALinux: FC = () => ( {'certipy req -u computername -p Passw0rd -ca corp-DC-CA -target ca.corp.local -template ESC14'} - If the enrollment fails with an error message stating that the Email or DNS name is unavailable and cannot - be added to the Subject or Subject Alternate name, then it is because the enrollee principal does not have - their mail or dNSHostName attribute set, which is required by the certificate template. The mail attribute - can be set on both user and computer objects but the dNSHostName attribute can only be set on computer - objects. Computers have validated write permission to their own dNSHostName attribute by default, but - neither users nor computers can write to their own mail attribute by default. - - - The abuse is possible with the strong explicit certificate mappings X509IssuerSerialNumber or - X509SHA1PublicKey. In this example, we use X509SHA1PublicKey. +

+ If the enrollment fails with an error message stating that the Email or DNS name is unavailable and + cannot be added to the Subject or Subject Alternate name, then it is because the enrollee principal does + not have their mail or dNSHostName attribute set, which is required by the certificate template. The + mail attribute can be set on both user and computer objects but the dNSHostName attribute can only be + set on computer objects. Computers have validated write permission to their own dNSHostName attribute by + default, but neither users nor computers can write to their own mail attribute by default. +

+

+ The abuse is possible with the strong explicit certificate mappings X509IssuerSerialNumber or + X509SHA1PublicKey. In this example, we use X509SHA1PublicKey. +

+

Get the SHA1 hash of the certificate using openssl:

- Get the SHA1 hash of the certificate using openssl: {`openssl pkcs12 -info -in computername.pfx -nokeys | openssl x509 -noout -sha1 -fingerprint | tr -d ':' | tr '[:upper:]' '[:lower:]' … @@ -123,11 +158,15 @@ sha1 fingerprint=f61331a504cff8cb5e60c269632c31aa3032a54a`} export const AdcsEsc14ScenarioAWindows: FC = () => { return ( <> - ADCS ESC14 Scenario A + + ADCS ESC14 Scenario A + - An attacker can add an explicit certificate mapping in the altSecurityIdentities of the target referring - to a certificate in the attacker's possession, and then use this certificate to authenticate as the - target. +

+ An attacker can add an explicit certificate mapping in the altSecurityIdentities of the target + referring to a certificate in the attacker's possession, and then use this certificate to + authenticate as the target. +

The certificate must meet the following requirements: @@ -161,6 +200,34 @@ export const AdcsEsc14ScenarioAWindows: FC = () => { ). + + +

+ If the attacker cannot obtain a suitable certificate from the target environment, they may also be + able to use a third-party Client Authentication certificate. +

+

+ This works because explicit certificate mapping differs from implicit certificate mapping. Implicit + mapping requires the certificate to chain to a CA certificate in the domain controller's NTAuth + store. Explicit mapping does not. For explicit mapping, the certificate only needs to chain to a + trusted root CA on the domain controller. +

+

+ Windows trusts many third-party root CAs by default, so an attacker may be able to buy or steal a + third-party certificate with the Client Authentication EKU and use it for ESC14 Scenario A. For + example, providers such as{' '} + + SSL.com + {' '} + are trusted by Windows and offer client authentication certificates. +

+
+ + Execution + Obtain a certificate meeting the above requirements for example by dumping a certificate from a computer, or enrolling a new certificate as a computer using Certify (2.0): @@ -171,15 +238,28 @@ export const AdcsEsc14ScenarioAWindows: FC = () => { } - Save the certificate as cert.pem and the private key as cert.key. Use certutil to obtain the certificate - as a PFX file: +

+ If the enrollment fails with an error message stating that the Email or DNS name is unavailable and + cannot be added to the Subject or Subject Alternate name, then it is because the enrollee principal + does not have their mail or dNSHostName attribute set, which is required by the certificate + template. The mail attribute can be set on both user and computer objects but the dNSHostName + attribute can only be set on computer objects. Computers have validated write permission to their + own dNSHostName attribute by default, but neither users nor computers can write to their own mail + attribute by default. +

+

+ Save the certificate as cert.pem and the private key as cert.key. Use certutil to obtain the + certificate as a PFX file: +

{'certutil.exe -MergePFX .\\cert.pem .\\cert.pfx'} - The abuse is possible with the strong explicit certificate mappings X509IssuerSerialNumber or - X509SHA1PublicKey. In this example, we use X509SHA1PublicKey. +

+ The abuse is possible with the strong explicit certificate mappings X509IssuerSerialNumber or + X509SHA1PublicKey. In this example, we use X509SHA1PublicKey. +

+

Get the SHA1 hash of the certificate public key using certutil:

- Get the SHA1 hash of the certificate public key using certutil: {`certutil.exe -dump -v .\\cert.pfx … diff --git a/packages/javascript/bh-shared-ui/src/components/HelpTexts/WriteAltSecurityIdentities/LinuxAbuse.tsx b/packages/javascript/bh-shared-ui/src/components/HelpTexts/WriteAltSecurityIdentities/LinuxAbuse.tsx index 81b71d343df2..241f3318fe2a 100644 --- a/packages/javascript/bh-shared-ui/src/components/HelpTexts/WriteAltSecurityIdentities/LinuxAbuse.tsx +++ b/packages/javascript/bh-shared-ui/src/components/HelpTexts/WriteAltSecurityIdentities/LinuxAbuse.tsx @@ -22,7 +22,9 @@ const LinuxAbuse: FC = () => { return ( <> - The write access to the AltSecurityIdentities may enable an ADCS ESC14 Scenario A attack. +

+ The write access to the AltSecurityIdentities may enable an ADCS ESC14 Scenario A attack. +

diff --git a/packages/javascript/bh-shared-ui/src/components/HelpTexts/WriteAltSecurityIdentities/WindowsAbuse.tsx b/packages/javascript/bh-shared-ui/src/components/HelpTexts/WriteAltSecurityIdentities/WindowsAbuse.tsx index a1e3d32c57d6..3ac394903aea 100644 --- a/packages/javascript/bh-shared-ui/src/components/HelpTexts/WriteAltSecurityIdentities/WindowsAbuse.tsx +++ b/packages/javascript/bh-shared-ui/src/components/HelpTexts/WriteAltSecurityIdentities/WindowsAbuse.tsx @@ -23,7 +23,9 @@ const WindowsAbuse: FC = () => { return ( <> - The write access to the AltSecurityIdentities may enable an ADCS ESC14 Scenario A attack. +

+ The write access to the AltSecurityIdentities may enable an ADCS ESC14 Scenario A attack. +

diff --git a/packages/javascript/bh-shared-ui/src/components/HelpTexts/WritePublicInformation/LinuxAbuse.tsx b/packages/javascript/bh-shared-ui/src/components/HelpTexts/WritePublicInformation/LinuxAbuse.tsx index 7b9f85a15b8a..59b349ba9361 100644 --- a/packages/javascript/bh-shared-ui/src/components/HelpTexts/WritePublicInformation/LinuxAbuse.tsx +++ b/packages/javascript/bh-shared-ui/src/components/HelpTexts/WritePublicInformation/LinuxAbuse.tsx @@ -23,18 +23,20 @@ const LinuxAbuse: FC = () => { return ( <> - The write access to the AltSecurityIdentities may enable an ADCS ESC14 Scenario A attack. - - - Alternatively, the write access to the SPN enable a targeted Kerberoasting attack against user accounts - with a weak password. See the{' '} - - WriteSPN - {' '} - edge for more details. +

+ The write access to the AltSecurityIdentities may enable an ADCS ESC14 Scenario A attack. +

+

+ Alternatively, the write access to the SPN enable a targeted Kerberoasting attack against user + accounts with a weak password. See the{' '} + + WriteSPN + {' '} + edge for more details. +

diff --git a/packages/javascript/bh-shared-ui/src/components/HelpTexts/WritePublicInformation/WindowsAbuse.tsx b/packages/javascript/bh-shared-ui/src/components/HelpTexts/WritePublicInformation/WindowsAbuse.tsx index 9fdd1eed90a1..44db012fccca 100644 --- a/packages/javascript/bh-shared-ui/src/components/HelpTexts/WritePublicInformation/WindowsAbuse.tsx +++ b/packages/javascript/bh-shared-ui/src/components/HelpTexts/WritePublicInformation/WindowsAbuse.tsx @@ -23,18 +23,20 @@ const WindowsAbuse: FC = () => { return ( <> - The write access to the AltSecurityIdentities may enable an ADCS ESC14 Scenario A attack. - - - Alternatively, the write access to the SPN enable a targeted Kerberoasting attack against user accounts - with a weak password. See the{' '} - - WriteSPN - {' '} - edge for more details. +

+ The write access to the AltSecurityIdentities may enable an ADCS ESC14 Scenario A attack. +

+

+ Alternatively, the write access to the SPN enable a targeted Kerberoasting attack against user + accounts with a weak password. See the{' '} + + WriteSPN + {' '} + edge for more details. +

diff --git a/packages/javascript/bh-shared-ui/src/components/Navigation/MainNav.tsx b/packages/javascript/bh-shared-ui/src/components/Navigation/MainNav.tsx index 9e3c7b94f7de..d53f7541c0e1 100644 --- a/packages/javascript/bh-shared-ui/src/components/Navigation/MainNav.tsx +++ b/packages/javascript/bh-shared-ui/src/components/Navigation/MainNav.tsx @@ -199,8 +199,8 @@ const MainNav: FC<{ mainNavData: MainNavData }> = ({ mainNavData }) => { 'bg-neutral-4 dark:bg-neutral-5', 'hover:bg-[#B2B8BE] dark:hover:bg-neutral-3', 'active:ring-0 active:bg-[#C0C6CB] dark:active:bg-neutral-2', - 'focus-visible:text-[#121212] dark:focus-visible:text-white', - 'focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-focus focus-visible:ring-offset-focus-offset', + 'focus:text-[#121212] dark:focus:text-white', + 'focus:ring-2 focus:ring-offset-2 focus:ring-secondary dark:focus:ring-offset-[#1F1F1F]', { 'rotate-180 left-[16.75rem]': isExpanded, 'left-[2.75rem]': !isExpanded, diff --git a/packages/javascript/bh-shared-ui/src/components/NodeIcon/NodeIcon.tsx b/packages/javascript/bh-shared-ui/src/components/NodeIcon/NodeIcon.tsx index 2a775dedc93d..0f61ed6ffb9b 100644 --- a/packages/javascript/bh-shared-ui/src/components/NodeIcon/NodeIcon.tsx +++ b/packages/javascript/bh-shared-ui/src/components/NodeIcon/NodeIcon.tsx @@ -17,16 +17,14 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from 'doodle-ui'; import { useCustomNodeKinds } from '../../hooks/useCustomNodeKinds'; -import { cn } from '../../utils'; import { EntityKinds, MetaDetailNodeKind, MetaNodeKind } from '../../utils/content'; import { GetIconInfo } from '../../utils/icons'; interface NodeIconProps { nodeType?: EntityKinds | string; - className?: string; } -function NodeIcon({ nodeType = '', className }: NodeIconProps) { +function NodeIcon({ nodeType = '' }: NodeIconProps) { const customIcons = useCustomNodeKinds().data ?? {}; const iconInfo = GetIconInfo(nodeType, customIcons); @@ -36,10 +34,7 @@ function NodeIcon({ nodeType = '', className }: NodeIconProps) { contentProps={{ className: 'bg-neutral-5 border-none text-contrast dark:text-contrast' }}>
{nodeType === MetaNodeKind || nodeType === MetaDetailNodeKind ? ( diff --git a/packages/javascript/bh-shared-ui/src/components/SearchResultItem/SearchResultItem.tsx b/packages/javascript/bh-shared-ui/src/components/SearchResultItem/SearchResultItem.tsx index 8988648e6d9b..a7d0a338911b 100644 --- a/packages/javascript/bh-shared-ui/src/components/SearchResultItem/SearchResultItem.tsx +++ b/packages/javascript/bh-shared-ui/src/components/SearchResultItem/SearchResultItem.tsx @@ -40,9 +40,9 @@ const SearchResultItem: FC<{ dense style={style} className={cn( - 'group hover:bg-secondary hover:text-common-white hover:dark:bg-secondary-variant-2 hover:dark:text-common-dark focus:bg-secondary focus:text-common-white focus:dark:bg-secondary-variant-2 focus:dark:text-common-dark focus-visible:bg-secondary focus-visible:text-common-white focus-visible:dark:bg-secondary-variant-2 focus-visible:dark:text-common-dark', + 'hover:bg-secondary hover:text-neutral-light-1 hover:dark:bg-secondary-variant-2 hover:dark:text-neutral-dark-1', { - 'bg-secondary text-common-white dark:bg-secondary-variant-2 dark:text-common-dark': + 'bg-secondary text-neutral-light-1 dark:bg-secondary-variant-2 dark:text-neutral-dark-1': highlightedIndex === index, } )} @@ -58,15 +58,7 @@ const SearchResultItem: FC<{ display: 'flex', alignItems: 'center', }}> - + ))} @@ -184,7 +180,7 @@ const SimpleEnvironmentSelector: React.FC<{ return (
  • ); diff --git a/packages/javascript/bh-shared-ui/src/constants.ts b/packages/javascript/bh-shared-ui/src/constants.ts index b5a89986aa47..ea4d82994ad9 100644 --- a/packages/javascript/bh-shared-ui/src/constants.ts +++ b/packages/javascript/bh-shared-ui/src/constants.ts @@ -124,38 +124,11 @@ export const useStyles = makeStyles((theme: Theme) => ({ }, })); -const focusRingStyles = (palette: Palette) => ({ - outline: `2px solid ${palette.color.links}`, - outlineOffset: '2px', -}); - -const inheritFocusedIconStyles = { - '& svg': { - color: 'inherit', - fill: 'currentColor', - }, - '& svg *': { - color: 'inherit', - fill: 'currentColor', - }, -}; - export const themedComponents = (palette: Palette): ThemeOptions['components'] => ({ - MuiButtonBase: { - styleOverrides: { - root: { - '&.Mui-focusVisible': { - ...focusRingStyles(palette), - ...inheritFocusedIconStyles, - }, - }, - }, - }, MuiAccordionSummary: { styleOverrides: { root: { flexDirection: 'row-reverse', - '&.Mui-focusVisible': focusRingStyles(palette), }, content: { marginRight: '4px', @@ -166,13 +139,6 @@ export const themedComponents = (palette: Palette): ThemeOptions['components'] = styleOverrides: { root: { color: palette.color.links, - borderRadius: '2px', - '&:focus-visible': { - ...focusRingStyles(palette), - textDecoration: 'underline', - textDecorationThickness: '2px', - textUnderlineOffset: '2px', - }, }, }, }, @@ -235,14 +201,6 @@ export const themedComponents = (palette: Palette): ThemeOptions['components'] = }, }, }, - styleOverrides: { - option: { - '&.Mui-focused, &[aria-selected="true"].Mui-focused': { - backgroundColor: addOpacityToHex(palette.color.links, 16), - boxShadow: `inset 3px 0 0 ${palette.color.links}`, - }, - }, - }, }, MuiDialogActions: { styleOverrides: { @@ -266,36 +224,12 @@ export const themedComponents = (palette: Palette): ThemeOptions['components'] = MuiCheckbox: { styleOverrides: { root: { - '&.Mui-focusVisible': { - ...focusRingStyles(palette), - borderRadius: '4px', - }, '& svg': { color: palette.color.primary, }, }, }, }, - MuiRadio: { - styleOverrides: { - root: { - '&.Mui-focusVisible': { - ...focusRingStyles(palette), - borderRadius: '50%', - }, - }, - }, - }, - MuiSwitch: { - styleOverrides: { - root: { - '&:has(.Mui-focusVisible)': { - ...focusRingStyles(palette), - borderRadius: '999px', - }, - }, - }, - }, MuiTabs: { styleOverrides: { root: { @@ -320,35 +254,6 @@ export const themedComponents = (palette: Palette): ThemeOptions['components'] = }, }, }, - MuiTab: { - styleOverrides: { - root: { - '&.Mui-focusVisible': { - ...focusRingStyles(palette), - ...inheritFocusedIconStyles, - }, - }, - }, - }, - MuiMenuItem: { - styleOverrides: { - root: { - '&.Mui-focusVisible, &:focus-visible': { - backgroundColor: addOpacityToHex(palette.color.links, 16), - boxShadow: `inset 3px 0 0 ${palette.color.links}`, - ...inheritFocusedIconStyles, - }, - }, - }, - }, - MuiTableSortLabel: { - styleOverrides: { - root: { - borderRadius: '2px', - '&.Mui-focusVisible, &:focus-visible': focusRingStyles(palette), - }, - }, - }, MuiAlert: { styleOverrides: { root: { diff --git a/packages/javascript/bh-shared-ui/src/views/Explore/ExploreSearch/SavedQueries/SaveQueryActionMenu.tsx b/packages/javascript/bh-shared-ui/src/views/Explore/ExploreSearch/SavedQueries/SaveQueryActionMenu.tsx index 9b2e561d1d94..71c840e7d8b5 100644 --- a/packages/javascript/bh-shared-ui/src/views/Explore/ExploreSearch/SavedQueries/SaveQueryActionMenu.tsx +++ b/packages/javascript/bh-shared-ui/src/views/Explore/ExploreSearch/SavedQueries/SaveQueryActionMenu.tsx @@ -13,7 +13,7 @@ // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 -import { Button, Popover, PopoverContent, PopoverTrigger } from 'doodle-ui'; +import { Popover, PopoverContent, PopoverTrigger } from 'doodle-ui'; import { FC, KeyboardEvent, MouseEvent } from 'react'; import { AppIcon } from '../../../../components'; import { adaptClickHandlerToKeyDown } from '../../../../utils/adaptClickHandlerToKeyDown'; @@ -27,15 +27,15 @@ const SaveQueryActionMenu: FC = ({ saveAs }) => { saveAs(); }; - const listItemStyles = - 'px-2 py-3 cursor-pointer hover:bg-neutral-4 focus-visible:bg-neutral-4 focus-visible:shadow-[inset_3px_0_0_var(--focus-ring)]'; + const listItemStyles = 'px-2 py-3 cursor-pointer hover:bg-neutral-light-4 dark:hover:bg-neutral-dark-4'; return ( - event.stopPropagation()}> - + event.stopPropagation()}> +
    = ({
    {iconDefinition ? ( - + ) : ( - + )}
    diff --git a/packages/javascript/doodle-ui/src/components/Accordion/Accordion.tsx b/packages/javascript/doodle-ui/src/components/Accordion/Accordion.tsx index 6ada830d64c3..b8103c8374ac 100644 --- a/packages/javascript/doodle-ui/src/components/Accordion/Accordion.tsx +++ b/packages/javascript/doodle-ui/src/components/Accordion/Accordion.tsx @@ -36,7 +36,7 @@ const AccordionHeader = React.forwardRef< svg]:rotate-180 p-4', + 'flex flex-1 gap-1 items-center font-bold transition-all hover:underline [&[data-state=open]>svg]:rotate-180 p-4', className )} {...props}> diff --git a/packages/javascript/doodle-ui/src/components/Alert/Alert.tsx b/packages/javascript/doodle-ui/src/components/Alert/Alert.tsx index 7ed68ecbde2b..7973fae6fbb1 100644 --- a/packages/javascript/doodle-ui/src/components/Alert/Alert.tsx +++ b/packages/javascript/doodle-ui/src/components/Alert/Alert.tsx @@ -68,7 +68,7 @@ const Alert = forwardRef< {action && ( )} diff --git a/packages/javascript/doodle-ui/src/components/Breadcrumbs/Breadcrumbs.tsx b/packages/javascript/doodle-ui/src/components/Breadcrumbs/Breadcrumbs.tsx index c52f754c6f5a..c34d738d761d 100644 --- a/packages/javascript/doodle-ui/src/components/Breadcrumbs/Breadcrumbs.tsx +++ b/packages/javascript/doodle-ui/src/components/Breadcrumbs/Breadcrumbs.tsx @@ -56,16 +56,7 @@ const BreadcrumbLink = React.forwardRef< >(({ asChild, className, ...props }, ref) => { const Comp = asChild ? Slot : 'a'; - return ( - - ); + return ; }); BreadcrumbLink.displayName = 'BreadcrumbLink'; diff --git a/packages/javascript/doodle-ui/src/components/Button/Button.tsx b/packages/javascript/doodle-ui/src/components/Button/Button.tsx index 25bdb15abddf..91d0c8fcd120 100644 --- a/packages/javascript/doodle-ui/src/components/Button/Button.tsx +++ b/packages/javascript/doodle-ui/src/components/Button/Button.tsx @@ -19,23 +19,21 @@ import * as React from 'react'; import { cn } from '../utils'; export const ButtonVariants = cva( - 'inline-flex items-center justify-center whitespace-nowrap h-10 px-6 py-2 rounded-3xl text-sm transition-colors hover:underline focus:outline-none focus-visible:focus-ring disabled:pointer-events-none disabled:opacity-50 active:no-underline', + 'inline-flex items-center justify-center whitespace-nowrap h-10 px-6 py-2 rounded-3xl text-sm ring-offset-background transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 active:no-underline', { variants: { variant: { - primary: - 'bg-primary text-white dark:text-neutral-dark-1 shadow-outer-1 hover:bg-secondary focus-visible:bg-secondary', - secondary: - 'bg-neutral-light-4 text-neutral-dark-1 shadow-outer-1 dark:bg-neutral-dark-5 dark:text-white hover:bg-secondary hover:text-white dark:hover:bg-secondary dark:hover:text-neutral-dark-1 active:bg-neutral-light-5 active:text-neutral-dark-1 dark:active:bg-neutral-dark-5 dark:active:text-white focus-visible:bg-secondary focus-visible:text-white dark:focus-visible:bg-secondary dark:focus-visible:text-neutral-dark-1 disabled:bg-neutral-light-3 disabled:text-text-disabled disabled:shadow-none disabled:!opacity-100 dark:disabled:bg-neutral-dark-5 dark:disabled:text-text-disabled', + primary: 'bg-primary text-white shadow-outer-1 hover:bg-secondary', + secondary: 'bg-neutral-light-4 text-neutral-dark-1 shadow-outer-1 hover:bg-secondary hover:text-white', tertiary: - 'bg-transparent border-2 border-neutral-light-5 shadow-outer-1 hover:bg-tertiary dark:hover:text-neutral-dark-1 hover:border-tertiary focus-visible:bg-tertiary dark:focus-visible:text-neutral-dark-1 focus-visible:border-tertiary', + 'bg-transparent border-2 border-neutral-light-5 shadow-outer-1 hover:bg-tertiary dark:hover:text-neutral-dark-1 hover:border-tertiary', transparent: - 'bg-transparent border border-neutral-5 dark:text-white hover:bg-primary hover:text-white hover:border-primary hover:no-underline focus-visible:bg-primary focus-visible:text-white focus-visible:border-primary', - text: 'text-primary dark:text-primary hover:text-secondary dark:hover:text-secondary active:text-primary-variant dark:active:text-primary focus-visible:text-secondary dark:focus-visible:text-secondary disabled:text-text-disabled disabled:!opacity-100 dark:disabled:text-text-disabled', - icon: 'rounded-full text-neutral-dark-1 bg-neutral-light-5 p-0 size-10 shadow-outer-1 hover:border-2 hover:border-secondary focus-visible:border-2 focus-visible:border-secondary active:border-none', + 'bg-transparent border border-neutral-5 dark:text-white hover:bg-primary hover:text-white hover:border-primary hover:no-underline', + text: 'text-neutral-dark-5 dark:text-neutral-light-5', + icon: 'rounded-full text-neutral-dark-1 bg-neutral-light-5 p-0 size-10 shadow-outer-1 hover:border-2 hover:border-secondary active:border-none', }, fontColor: { - primary: 'text-primary dark:text-primary', + primary: 'text-primary dark:text-secondary-variant-2', }, size: { small: 'h-9 px-4 py-1 text-xs', diff --git a/packages/javascript/doodle-ui/src/components/Carousel/Carousel.tsx b/packages/javascript/doodle-ui/src/components/Carousel/Carousel.tsx index 9eee8bc76b7c..4ffddcbcc7ea 100644 --- a/packages/javascript/doodle-ui/src/components/Carousel/Carousel.tsx +++ b/packages/javascript/doodle-ui/src/components/Carousel/Carousel.tsx @@ -240,7 +240,7 @@ const CarouselDots = React.forwardRef onDotButtonClick(index)}> diff --git a/packages/javascript/doodle-ui/src/components/Checkbox/Checkbox.tsx b/packages/javascript/doodle-ui/src/components/Checkbox/Checkbox.tsx index fd66eaf11148..43e04e34c0dc 100644 --- a/packages/javascript/doodle-ui/src/components/Checkbox/Checkbox.tsx +++ b/packages/javascript/doodle-ui/src/components/Checkbox/Checkbox.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import { cn } from '../utils'; const CheckboxVariants = cva( - 'peer shrink-0 rounded-sm border-2 border-text-main focus:outline-none focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-text-main data-[state=checked]:text-neutral-1', + 'peer shrink-0 rounded-sm border-2 border-neutral-dark-1 dark:border-neutral-light-1 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-neutral-dark-1 data-[state=checked]:text-neutral-light-1 dark:data-[state=checked]:bg-neutral-light-1 dark:data-[state=checked]:text-neutral-dark-1', { variants: { size: { diff --git a/packages/javascript/doodle-ui/src/components/DataTable/DataTable.tsx b/packages/javascript/doodle-ui/src/components/DataTable/DataTable.tsx index 81d6cd93a2d1..7fdc7d4dabcb 100644 --- a/packages/javascript/doodle-ui/src/components/DataTable/DataTable.tsx +++ b/packages/javascript/doodle-ui/src/components/DataTable/DataTable.tsx @@ -571,13 +571,6 @@ const DataTable = (props: DataTableProps) => { tableBodyRowRest = rest; } - const { - onKeyDown: onTableBodyRowKeyDown, - role: tableBodyRowRole, - tabIndex: tableBodyRowTabIndex, - ...restTableBodyRowAttributes - } = tableBodyRowRest as React.HTMLAttributes; - return ( (props: DataTableProps) => { e.stopPropagation(); handleRowClick(row); }} - onKeyDown={(event) => { - onTableBodyRowKeyDown?.(event); - - if ( - event.defaultPrevented || - event.currentTarget !== event.target || - !onRowClick || - (event.key !== 'Enter' && event.key !== ' ') - ) { - return; - } - - event.preventDefault(); - event.stopPropagation(); - handleRowClick(row); - }} - role={tableBodyRowRole} - tabIndex={tableBodyRowTabIndex ?? (onRowClick ? 0 : undefined)} data-state={row.getIsSelected() && 'selected'} className={cn( 'hover:bg-neutral-light-4 dark:hover:bg-neutral-dark-4', @@ -615,13 +590,11 @@ const DataTable = (props: DataTableProps) => { 'bg-neutral-light-2 dark:bg-neutral-dark-2': row.index % 2 !== 0, 'cursor-pointer': onRowClick, 'cursor-default': !onRowClick, - 'focus:outline-none focus-visible:focus-ring focus-visible:bg-neutral-light-4 dark:focus-visible:bg-neutral-dark-4': - onRowClick, }, propsClassName )} - {...restTableBodyRowAttributes} + {...tableBodyRowRest} style={{ height: `${virtualRow.size}px`, transform: `translateY(${virtualRow.start - index * virtualRow.size}px)`, diff --git a/packages/javascript/doodle-ui/src/components/DataTable/StorybookExample/utils.tsx b/packages/javascript/doodle-ui/src/components/DataTable/StorybookExample/utils.tsx index 1d6cda2f16a5..ad02747bf531 100644 --- a/packages/javascript/doodle-ui/src/components/DataTable/StorybookExample/utils.tsx +++ b/packages/javascript/doodle-ui/src/components/DataTable/StorybookExample/utils.tsx @@ -52,10 +52,7 @@ export const getColumns = (sortOrder?: string | null, handleSort?: (sortBy: stri return Action Menu; }, cell: () => ( - ), @@ -96,10 +93,7 @@ export const getColumns = (sortOrder?: string | null, handleSort?: (sortBy: stri Tier Zero Principal {sortOrder !== undefined ? ( -