[CB] Replace material ui with native css variables and tailwind utilities (#4188)

* dbeaver/pro#8433 initial version of material ui refactor

* fixes arrow colors

* fixes arrow colors 2

* fixes colors

* pr fixes

* removes layers due to it loses styles specificity race

* fixes autocomplete styles

* adds variables for typography

* moves switch logic to module styles

* removes elevation styles

* removes unused code

* migrates ripple effect to tw class

* Revert "migrates ripple effect to tw class"

This reverts commit 78229ac007.

* uses classname theme-typography for button

* adds elevation styles

* adds elevation styles 2

* moves theme ripple

* reverts scss for sql editor

* reverts scss for sql editor 2

* adds tailwindcss utilities + example

* Revert "adds tailwindcss utilities + example"

This reverts commit 20ca1b787c.

* creates tailwindcss plugin with shadow tokens + spread it across the app

* moves typography to the tailwindcss styles

* refactors sql editor styles

* moves styles from tailwindcss folder to styles

* moves ripple to tailwindcss plugin

* removes unused files

* removes unused file index

* removes redundant tailwindcss import

* adds animation layer for tailwindcss

* refactors animations

* build fix

* removes redundant imports of tailwindcss for styles

* removes layer components to keep some styles for switch

* removes animation from ripple effect

* makes ripple effect more contrast

* fixes fonts across the app to json view has correct font-mono from the tailwindcss box

* deletes module ts

* Revert "removes layer components to keep some styles for switch"

This reverts commit ee8b0e199e.

* fixes race for switch bold style

* changes ripple from 7% to 9%

* Reduce hover opacity in ripple effect (#4260)

* Reduce hover opacity in ripple effect

* Update ripple.css

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
This commit is contained in:
sergeyteleshev
2026-04-02 18:24:19 +02:00
committed by GitHub
co-authored by mr-anton-t
parent a6a1916299
commit ea36247797
81 changed files with 1190 additions and 1488 deletions
@@ -42,10 +42,6 @@
min-width: 64px;
font-family: Roboto, sans-serif;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-weight: 500;
letter-spacing: 0.0892857143em;
text-decoration: none;
+25 -17
View File
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -8,7 +8,7 @@
import { createElement } from 'react';
import { observable } from 'mobx';
import { observer } from 'mobx-react-lite';
import { Button as UIKitButton, ButtonIcon } from '@dbeaver/ui-kit';
import { Button as UIKitButton, ButtonIcon, clsx } from '@dbeaver/ui-kit';
import { IconOrImage } from './IconOrImage.js';
import { useObjectRef } from './useObjectRef.js';
@@ -19,20 +19,20 @@ import './Button.css';
export type ButtonProps = (React.ButtonHTMLAttributes<HTMLButtonElement | HTMLAnchorElement> &
React.LinkHTMLAttributes<HTMLLinkElement | HTMLButtonElement> &
React.HTMLAttributes<HTMLDivElement>) & {
loading?: boolean;
icon?: string;
viewBox?: string;
iconPlacement?: 'start' | 'end';
iconSize?: number;
variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
size?: 'small' | 'medium' | 'large';
tag?: 'button' | 'a' | 'div';
href?: string;
target?: '_blank' | '_self' | '_parent' | '_top';
loader?: boolean;
onClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement | HTMLLinkElement | HTMLDivElement> | (() => Promise<any>);
download?: boolean;
};
loading?: boolean;
icon?: string;
viewBox?: string;
iconPlacement?: 'start' | 'end';
iconSize?: number;
variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
size?: 'small' | 'medium' | 'large';
tag?: 'button' | 'a' | 'div';
href?: string;
target?: '_blank' | '_self' | '_parent' | '_top';
loader?: boolean;
onClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement | HTMLLinkElement | HTMLDivElement> | (() => Promise<any>);
download?: boolean;
};
export const Button = observer<ButtonProps>(function Button({
children,
@@ -81,7 +81,15 @@ export const Button = observer<ButtonProps>(function Button({
const Tag = createElement(tag);
return (
<UIKitButton render={Tag} {...rest} loading={loading} type={type} disabled={disabled} className={className} onClick={state.click}>
<UIKitButton
render={Tag}
{...rest}
loading={loading}
type={type}
disabled={disabled}
className={clsx(className, 'theme-typography')}
onClick={state.click}
>
{icon && (
<ButtonIcon placement={iconPlacement}>
<IconOrImage width={iconSize} icon={icon} viewBox={viewBox} />
@@ -6,7 +6,7 @@
* you may not use this file except in compliance with the License.
*/
.dialog {
composes: theme-background-surface theme-text-on-surface theme-elevation-z10 from global;
composes: theme-background-surface theme-text-on-surface from global;
&.fixedSize[data-size='small'] {
width: 404px;
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -61,7 +61,7 @@ export const CommonDialogWrapper = observer<CommonDialogWrapperProps, HTMLDivEle
aria-label={ariaLabel}
open={context.visible}
data-size={size}
className={s(computedStyles, { dialog: true, fixedSize, fixedWidth, freeHeight }, className)}
className={s(computedStyles, { dialog: true, fixedSize, fixedWidth, freeHeight }, 'tw:shadow-xlarge', className)}
autoFocusOnShow={autoFocusOnShow}
autoFocusOnHide={autoFocusOnHide}
initialFocus={initialFocus as HTMLElement | React.RefObject<HTMLElement> | null | undefined}
@@ -10,7 +10,7 @@
}
.error {
composes: theme-background-surface theme-text-on-surface theme-elevation-z10 from global;
composes: theme-background-surface theme-text-on-surface from global;
border-radius: 0.25rem;
}
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -87,7 +87,7 @@ const NestedDialog: React.FC<NestedDialogType> = function NestedDialog({ dialog,
return (
<DialogContext.Provider value={context}>
<ErrorBoundary className={s(styles, { error: true })} remount onClose={rejectDialog}>
<ErrorBoundary className={s(styles, { error: true }, 'tw:shadow-xlarge')} remount onClose={rejectDialog}>
<DialogComponent
visible={visible}
payload={dialog.payload}
@@ -9,7 +9,7 @@
composes: theme-background-positive from global;
position: absolute;
opacity: 0;
transition: opacity 0.3s ease;
transition: opacity var(--duration-slow) var(--ease-soft);
bottom: 0;
right: 0;
box-sizing: border-box;
@@ -12,8 +12,8 @@
display: grid;
grid-template-rows: 0fr;
transition-property: grid-template-rows;
transition-timing-function: ease-in-out;
transition-duration: 200ms;
transition-timing-function: var(--ease-smooth);
transition-duration: var(--duration-medium);
> * {
overflow: hidden;
@@ -36,7 +36,7 @@
opacity: 0.5;
width: var(--dbv-kit-disclosure-icon-size);
height: var(--dbv-kit-disclosure-icon-size);
transition: transform 150ms ease-in-out;
transition: transform var(--duration-medium) var(--ease-smooth);
transform-origin: center;
transform: rotate(-90deg);
}
@@ -6,7 +6,7 @@
* you may not use this file except in compliance with the License.
*/
.menu {
composes: theme-text-on-surface theme-background-surface theme-typography--caption theme-elevation-z3 from global;
composes: theme-text-on-surface theme-background-surface theme-typography--caption from global;
display: flex;
flex-direction: column;
max-height: 300px;
@@ -5,6 +5,7 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@layer components {
.field {
--dbv-kit-control-outline-offset: -8px;
@@ -41,34 +42,118 @@
border-width: var(--dbv-kit-control-outline-width);
}
}
}
.switchControl {
composes: theme-switch from global;
}
.switchControl {
position: relative;
display: inline-flex;
align-items: center;
width: 36px;
height: 20px;
vertical-align: middle;
outline: none;
flex-shrink: 0;
.disabled {
composes: theme-switch--disabled mdc-switch--disabled from global;
}
&:not(.disabled):hover .switchControlThumb {
box-shadow:
0px 3px 1px -2px rgba(0, 0, 0, 0.2),
0px 2px 2px 0px rgba(0, 0, 0, 0.14),
0px 1px 5px 0px rgba(0, 0, 0, 0.12),
0px 0px 0px 8px color-mix(in srgb, var(--theme-on-surface) 4%, transparent);
}
.checked {
composes: theme-switch--checked mdc-switch--checked from global;
}
&:not(.disabled):has(.switchInput:focus-visible) .switchControlThumb {
box-shadow:
0px 3px 1px -2px rgba(0, 0, 0, 0.2),
0px 2px 2px 0px rgba(0, 0, 0, 0.14),
0px 1px 5px 0px rgba(0, 0, 0, 0.12),
0px 0px 0px 12px color-mix(in srgb, var(--theme-on-surface) 8%, transparent);
}
}
.switchControlTrack {
composes: theme-switch__track from global;
}
.switchInput {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
margin: 0;
padding: 0;
z-index: 2;
.switchInput {
composes: theme-switch_native-control from global;
}
&:disabled {
cursor: default;
pointer-events: none;
}
}
.switchControlUnderlay {
composes: theme-switch__thumb-underlay from global;
}
.switchControlTrack {
box-sizing: border-box;
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
width: 100%;
height: 14px;
border: 1px solid var(--theme-on-surface, #000);
border-radius: 7px;
background-color: var(--theme-on-surface, #000);
opacity: 0.38;
border: none;
transition:
background-color var(--duration-fast) var(--ease-smooth-start),
border-color var(--duration-fast) var(--ease-smooth-start),
opacity var(--duration-fast) var(--ease-smooth-start);
}
.switchControlThumb {
composes: theme-switch__thumb from global;
.switchControlUnderlay {
margin-left: -2px;
display: flex;
align-items: center;
justify-content: center;
transition: margin-left var(--duration-fast) var(--ease-smooth-start);
}
.switchControlThumb {
box-sizing: border-box;
width: 20px;
height: 20px;
border: 10px solid var(--theme-switch-thumb, #fff);
border-radius: 50%;
background-color: var(--theme-surface, #fff);
box-shadow:
0px 3px 1px -2px rgba(0, 0, 0, 0.2),
0px 2px 2px 0px rgba(0, 0, 0, 0.14),
0px 1px 5px 0px rgba(0, 0, 0, 0.12);
pointer-events: none;
z-index: 1;
transition:
background-color var(--duration-fast) var(--ease-smooth-start),
border-color var(--duration-fast) var(--ease-smooth-start);
}
.checked {
& .switchControlTrack {
background-color: color-mix(in srgb, var(--theme-primary, #2a7cb4) 50%, transparent);
border-color: color-mix(in srgb, var(--theme-primary, #2a7cb4) 50%, transparent);
opacity: 1;
}
& .switchControlUnderlay {
margin-left: 18px;
}
& .switchControlThumb {
background-color: var(--theme-primary, #2a7cb4);
border-color: var(--theme-primary, #2a7cb4);
}
}
.disabled {
opacity: 0.38;
pointer-events: none;
}
}
.switchBody {
@@ -5,14 +5,39 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.switchBody {
composes: theme-switch_dense from global;
@layer components {
.switchBody {
& .switchControl {
width: 24px;
height: 16px;
}
& .switchControlTrack {
height: 10px;
border-radius: 5px;
}
& .switchControlUnderlay {
margin-left: -3px;
}
& .switchControlThumb {
width: 14px;
height: 14px;
border-width: 7px;
}
& .checked .switchControlUnderlay {
margin-left: 13px;
}
}
/* overrides bold label style from SwitchDense.module.css because of specificity */
.switchBody .fieldLabel {
font-weight: initial;
}
}
.fieldLabel {
composes: theme-typography--body2 from global;
}
/* overrides bold label style from SwitchDense.module.css because of specificity */
.switchBody .fieldLabel {
font-weight: initial;
}
@@ -5,10 +5,15 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.switchControl {
composes: theme-switch_primary from global;
}
@layer components {
.switchBody {
.switchControl {
width: 36px;
height: 20px;
}
.fieldLabel {
font-weight: 500;
.fieldLabel {
font-weight: 500;
}
}
}
@@ -20,26 +20,25 @@ interface AutocompletionProps {
onSelect?: (proposal: InputAutocompleteProposal) => void;
}
export const InputAutocompletionMenu = observer(forwardRef<HTMLDivElement, AutocompletionProps>(function InputAutocompletionMenu({
proposals,
onSelect,
}, ref) {
const styles = useS(BaseDropdownStyles);
export const InputAutocompletionMenu = observer(
forwardRef<HTMLDivElement, AutocompletionProps>(function InputAutocompletionMenu({ proposals, onSelect }, ref) {
const styles = useS(BaseDropdownStyles);
return (
<Popover.PopoverContent ref={ref} className={s(styles, { menu: true })} gutter={4} modal={false} autoFocusOnShow={false} unmountOnHide>
<Composite>
{proposals.map(proposal => (
<CompositeItem key={proposal.title} className={s(styles, { menuItem: true }, 'tw:w-full')} onClick={() => onSelect?.(proposal)}>
{proposal.icon && (
<div className={s(styles, { itemIcon: true })}>
<IconOrImage icon={proposal.icon} className={s(styles, { iconOrImage: true })} />
</div>
)}
<Text truncate>{proposal.displayString}</Text>
</CompositeItem>
))}
</Composite>
</Popover.PopoverContent>
);
}));
return (
<Popover.PopoverContent ref={ref} className={s(styles, { menu: true })} gutter={4} modal={false} autoFocusOnShow={false} unmountOnHide>
<Composite>
{proposals.map(proposal => (
<CompositeItem key={proposal.title} className={s(styles, { menuItem: true }, 'tw:w-full')} onClick={() => onSelect?.(proposal)}>
{proposal.icon && (
<div className={s(styles, { itemIcon: true })}>
<IconOrImage icon={proposal.icon} className={s(styles, { iconOrImage: true })} />
</div>
)}
<Text truncate>{proposal.displayString}</Text>
</CompositeItem>
))}
</Composite>
</Popover.PopoverContent>
);
}),
);
@@ -28,7 +28,7 @@
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity cubic-bezier(0.4, 0, 0.2, 1) 0.3s;
transition: opacity var(--duration-slow) var(--ease-smooth-start);
&:global(.animate) {
opacity: 1;
}
@@ -6,41 +6,41 @@
* you may not use this file except in compliance with the License.
*/
.overlay {
composes: theme-text-on-primary from global;
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: auto;
position: absolute;
margin: auto;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
box-shadow: none;
composes: theme-text-on-primary from global;
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: auto;
position: absolute;
margin: auto;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
box-shadow: none;
&.active {
display: flex;
}
&.active {
display: flex;
}
&.fill {
background-color: var(--theme-background-surface);
& .box {
box-shadow: none;
}
&.fill {
background-color: var(--theme-background-surface);
& .box {
box-shadow: none;
}
}
}
.box {
composes: theme-background-surface theme-text-on-surface theme-elevation-z6 from global;
display: flex;
flex-direction: column;
justify-content: center;
overflow: auto;
border-radius: 0.25rem;
align-items: normal;
max-width: calc(100% - 48px);
max-height: calc(100% - 48px);
composes: theme-background-surface theme-text-on-surface from global;
display: flex;
flex-direction: column;
justify-content: center;
overflow: auto;
border-radius: 0.25rem;
align-items: normal;
max-width: calc(100% - 48px);
max-height: calc(100% - 48px);
}
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ export const Overlay = observer<React.PropsWithChildren<Props>>(function Overlay
return (
<div className={s(styles, { overlay: true, active, fill }, className)}>
<div className={s(styles, { box: true })}>{children}</div>
<div className={s(styles, { box: true }, 'tw:shadow-large')}>{children}</div>
</div>
);
});
@@ -4,7 +4,7 @@
inset: 0;
z-index: 999;
background: rgb(0 0 0 / 0%);
transition: background ease-in-out 0.3s;
transition: background var(--duration-slow) var(--ease-smooth);
pointer-events: none;
&[data-active] {
@@ -5,8 +5,9 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.notification {
composes: theme-background-surface theme-text-on-surface theme-elevation-z5 from global;
composes: theme-background-surface theme-text-on-surface from global;
position: relative;
display: flex;
box-sizing: border-box;
@@ -18,8 +19,8 @@
opacity: 0;
border-radius: var(--theme-group-element-radius);
transition:
opacity 0.3s ease-in-out,
transform 0.5s ease-in-out;
opacity var(--duration-slow) var(--ease-smooth),
transform var(--duration-slowest) var(--ease-smooth);
transform: translateX(-100%);
&.mounted {
@@ -31,8 +32,8 @@
opacity: 0;
transform: translateX(-100%);
transition:
opacity 0.5s ease-in-out,
transform 0.5s ease-in-out;
opacity var(--duration-slowest) var(--ease-smooth),
transform var(--duration-slowest) var(--ease-smooth);
}
}
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@ export const SnackbarWrapper: React.FC<React.PropsWithChildren<Props>> = functio
role="alert"
aria-live="assertive"
aria-atomic="true"
className={s(styles, { notification: true, mounted, closing }, className)}
className={s(styles, { notification: true, mounted, closing }, 'tw:shadow-medium', className)}
>
{children}
{!persistent && onClose && (
@@ -5,6 +5,7 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.resizerControls {
composes: theme-background-background theme-text-on-secondary from global;
position: relative;
@@ -12,7 +13,7 @@
cursor: ew-resize;
user-select: none;
z-index: 1;
transition: background-color 0.3s ease-in-out;
transition: background-color var(--duration-slow) var(--ease-smooth);
&:before {
content: ' ';
@@ -5,12 +5,13 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.cell {
position: relative;
box-sizing: border-box;
height: 28px;
padding: 0 16px;
transition: padding ease-in-out 0.24s;
transition: padding var(--duration-medium) var(--ease-smooth);
&.nowrap,
&.ellipsis {
@@ -10,7 +10,7 @@
width: 16px;
height: 16px;
padding: 0;
transition: transform ease-in-out 0.2s;
transition: transform var(--duration-medium) var(--ease-smooth);
&.expanded {
transform: rotate(180deg);
@@ -20,7 +20,7 @@
cursor: pointer;
opacity: 0.5;
transform: rotate(-90deg);
transition: transform 0.15s ease-in-out;
transition: transform var(--duration-medium) var(--ease-smooth);
&.expanded {
transform: rotate(0deg);
@@ -40,15 +40,6 @@
"@dbeaver/cli": "workspace:*",
"@dbeaver/react-tests": "workspace:*",
"@fontsource/roboto": "^5",
"@material/button": "^4",
"@material/checkbox": "^4",
"@material/elevation": "^4",
"@material/layout-grid": "^4",
"@material/radio": "^4",
"@material/ripple": "^4",
"@material/switch": "^4",
"@material/theme": "^4",
"@material/typography": "^4",
"rimraf": "^6",
"typescript": "^5",
"typescript-plugin-css-modules": "^5",
@@ -14,11 +14,9 @@ import { type ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor';
import type { Style } from './ComponentStyle.js';
import './styles/main/base.pure.css';
import './styles/main/color.pure.scss';
import './styles/main/elevation.pure.scss';
import './styles/main/fonts.pure.css';
// TODO: important to keep normalize first
import './styles/main/normalize.pure.css';
import './styles/main/typography.pure.scss';
import './styles/UiIconButton.css';
import './styles/UiSpinner.css';
import './styles/UiInput.css';
@@ -6,21 +6,6 @@
* you may not use this file except in compliance with the License.
*/
@mixin stripes-background($color, $important: false) {
// background-image: linear-gradient(
// 45deg,
// transparent 37.5%,
// $color 37.5%,
// $color 50%,
// transparent 50%,
// transparent 87.5%,
// $color 87.5%,
// $color 100%
// );
// background-size: 8px 8px;
background-color: $color #{if($important, '!important', '')};
}
@mixin delimiter($color) {
hr {
border-color: $color;
@@ -6,90 +6,89 @@
* you may not use this file except in compliance with the License.
*/
@mixin colors($query: mdc-feature-all()) {
$feat-color: mdc-feature-create-target($query, color);
@mixin colors() {
// Export all theme colors as CSS variables
--theme-primary: #{$mdc-theme-primary};
--theme-on-primary: #{$mdc-theme-on-primary};
--theme-secondary: #{$mdc-theme-secondary};
--theme-on-secondary: #{$mdc-theme-on-secondary};
--theme-error: #{$mdc-theme-error};
--theme-surface: #{$mdc-theme-surface};
--theme-on-surface: #{$mdc-theme-on-surface};
--theme-background: #{$mdc-theme-background};
--theme-sub-secondary: #{$mdc-theme-sub-secondary};
--theme-on-sub-secondary: #{$mdc-theme-on-sub-secondary};
--theme-positive: #{$color-positive};
--theme-on-positive: #{$color-on-positive};
--theme-negative: #{$color-negative};
--theme-status: #{$color-status};
--theme-link-color: #{$link-color};
--theme-input-color: #{$input-color};
--theme-input-color-disabled: #{$input-color-disabled};
--theme-input-color-readonly: #{$input-color-readonly};
--theme-input-color-placeholder: #{$input-color-placeholder};
--theme-input-border: #{$input-border};
--theme-input-border-readonly: #{$input-border-readonly};
--theme-input-border-disabled: #{$input-border-disabled};
--theme-input-background: #{$input-background};
--theme-input-background-disabled: #{$input-background-disabled};
--theme-input-background-readonly: #{$input-background-readonly};
--theme-switch-thumb: #{lighten($mdc-theme-surface, 5%)};
/*:root {*/
@include mdc-feature-targets($feat-color) {
@each $style in map-keys($mdc-theme-property-values) {
--theme-#{$style}: #{map-get($mdc-theme-property-values, $style)};
// Text color variants derived from $mdc-theme-text-colors
// Map keys "light"/"dark" describe the ink color, not the background.
// "on-light" (on light background) needs dark ink, "on-dark" needs light ink.
$light-ink-colors: map-get($mdc-theme-text-colors, light);
$dark-ink-colors: map-get($mdc-theme-text-colors, dark);
@each $variant in (primary, secondary, sub-secondary, hint, disabled, icon, negative) {
--theme-text-#{$variant}-on-light: #{map-get($dark-ink-colors, $variant)};
--theme-text-#{$variant}-on-dark: #{map-get($light-ink-colors, $variant)};
}
// Theme color utility classes
@each $color-name in (primary, on-primary, secondary, on-secondary, error, on-error, surface, on-surface, background, positive, negative, status) {
&.theme-text-#{$color-name},
.theme-text-#{$color-name} {
color: var(--theme-#{$color-name});
svg,
& > svg {
fill: var(--theme-#{$color-name});
}
}
&.theme-border-color-#{$color-name},
.theme-border-color-#{$color-name} {
border-color: var(--theme-#{$color-name}) !important;
}
&.theme-fill-#{$color-name},
.theme-fill-#{$color-name} {
fill: var(--theme-#{$color-name});
}
}
/*}*/
@each $style in map-keys($mdc-theme-property-values) {
@if $style != 'background' and $style != 'surface' and $style != 'on-surface' {
&.theme-text-#{$style},
.theme-text-#{$style} {
@include theme-ripple-color($query, $style);
@include mdc-feature-targets($feat-color) {
@include mdc-theme-prop(color, $style, true);
}
// Text variant utility classes (text-primary-on-light, text-hint-on-light, etc.)
@each $variant in (primary, secondary, sub-secondary, hint, disabled, icon, negative) {
@each $tone in (light, dark) {
&.theme-text-text-#{$variant}-on-#{$tone},
.theme-text-text-#{$variant}-on-#{$tone} {
color: var(--theme-text-#{$variant}-on-#{$tone});
svg,
& > svg {
@include mdc-feature-targets($feat-color) {
@include mdc-theme-prop(fill, $style, true);
}
}
}
&.theme-border-color-#{$style},
.theme-border-color-#{$style} {
@include mdc-feature-targets($feat-color) {
@include mdc-theme-prop(border-color, $style, true);
}
}
&.theme-fill-#{$style},
.theme-fill-#{$style} {
@include mdc-feature-targets($feat-color) {
@include mdc-theme-prop(fill, $style, true);
}
}
} @else {
&.theme-text-#{$style},
.theme-text-#{$style} {
@include theme-ripple-color($query, $style);
@include mdc-feature-targets($feat-color) {
@include mdc-theme-prop(color, $style);
}
svg,
& > svg {
@include mdc-feature-targets($feat-color) {
@include mdc-theme-prop(fill, $style);
}
}
}
&.theme-background-#{$style},
.theme-background-#{$style} {
@include mdc-feature-targets($feat-color) {
@include mdc-theme-prop(background-color, $style);
}
}
&.theme-border-color-#{$style},
.theme-border-color-#{$style} {
@include mdc-feature-targets($feat-color) {
@include mdc-theme-prop(border-color, $style, true);
}
}
&.theme-fill-#{$style},
.theme-fill-#{$style} {
@include mdc-feature-targets($feat-color) {
@include mdc-theme-prop(fill, $style);
fill: var(--theme-text-#{$variant}-on-#{$tone});
}
}
}
}
// CSS rules for using primary and secondary (plus light/dark variants) as background colors.
@each $style in ('primary', 'secondary', 'positive') {
&.theme-background-#{$style},
.theme-background-#{$style} {
@include mdc-feature-targets($feat-color) {
@include mdc-theme-prop(background-color, $style, true);
}
// Background color classes
@each $color-name in (primary, secondary, surface, background, positive) {
&.theme-background-#{$color-name},
.theme-background-#{$color-name} {
background-color: var(--theme-#{$color-name});
}
}
}
@@ -36,7 +36,7 @@
width: 0;
height: 0;
}
/* clears the ‘X’ from Chrome */
/* clears the 'X' from Chrome */
&[type='search']::-webkit-search-decoration,
&[type='search']::-webkit-search-cancel-button,
&[type='search']::-webkit-search-results-button,
@@ -53,20 +53,21 @@
width: 100%;
border: 1px solid;
outline: none !important;
border-radius: $theme-form-element-radius;
border-radius: var(--theme-form-element-radius);
color: var(--theme-input-color);
border-color: var(--theme-input-border);
background-color: var(--theme-input-background);
@include mdc-theme-prop(color, input-color, false);
@include mdc-theme-prop(border-color, input-border, false);
@include mdc-theme-prop(background-color, input-background, false);
// we use box-shadow to overlap internal background-color style, we can't override it due to chrome bug
&:-internal-autofill-selected,
&:-internal-autofill-previewed {
-webkit-text-fill-color: $mdc-theme-on-secondary;
box-shadow: 0 0 0 50px $input-background inset;
-webkit-text-fill-color: var(--theme-on-secondary);
box-shadow: 0 0 0 50px var(--theme-input-background) inset;
}
&:user-invalid {
@include mdc-theme-prop(border-color, negative, false);
border-color: var(--theme-negative);
}
&[type='color'] {
@@ -81,36 +82,36 @@
&:focus,
&[data-focus='true'] {
@include mdc-theme-prop(border-color, primary, false);
border-color: var(--theme-primary);
}
&:not([data-select='true'])[readonly] {
@include mdc-theme-prop(color, input-color-readonly, false);
@include mdc-theme-prop(border-color, input-border-readonly, false);
@include mdc-theme-prop(background-color, input-background-readonly, false);
color: var(--theme-input-color-readonly);
border-color: var(--theme-input-border-readonly);
background-color: var(--theme-input-background-readonly);
opacity: 1;
&:-internal-autofill-selected,
&:-internal-autofill-previewed {
box-shadow: 0 0 0 50px $input-background-readonly inset;
box-shadow: 0 0 0 50px var(--theme-input-background-readonly) inset;
}
}
&[disabled] {
@include mdc-theme-prop(color, input-color-readonly, false);
@include mdc-theme-prop(border-color, input-border-readonly, false);
@include mdc-theme-prop(background-color, input-background-readonly, false);
color: var(--theme-input-color-readonly);
border-color: var(--theme-input-border-readonly);
background-color: var(--theme-input-background-readonly);
pointer-events: all;
opacity: 1;
&:-internal-autofill-selected,
&:-internal-autofill-previewed {
box-shadow: 0 0 0 50px $input-background-readonly inset;
box-shadow: 0 0 0 50px var(--theme-input-background-readonly) inset;
}
}
&[data-embedded='true'] {
&[disabled],
&:not([data-select='true'])[readonly] {
@include mdc-theme-prop(border-color, background, false);
@include mdc-theme-prop(background-color, input-background, false);
border-color: var(--theme-background);
background-color: var(--theme-input-background);
}
}
}
@@ -6,20 +6,10 @@
* you may not use this file except in compliance with the License.
*/
@import '@material/theme/mixins';
@import '@material/ripple/mixins';
@import '@material/button/mixins';
@import '@material/elevation/mixins';
@import '@material/typography/mixins';
@import './variables';
@import './theme';
@import './color-scheme';
@import './layout-grid';
@import './branding';
@import './theme-ripple';
@import './ripple';
@import './color';
@import './switch';
@import './placeholder';
@import './form-controls';
@import './link';
@@ -1,33 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@mixin placeholder {
.placeholder {
box-sizing: border-box;
overflow: hidden;
position: relative;
background: #f0f0f0;
border-radius: $theme-form-element-radius;
margin: 2px;
animation: wave 1.5s linear infinite;
}
@keyframes wave {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
}
@@ -1,31 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@mixin ripple-core-styles($query: mdc-feature-all()) {
$feat-structure: mdc-feature-create-target($query, structure);
.theme-ripple-surface {
@include mdc-ripple-surface($query: $query);
@include mdc-states($query: $query);
@include mdc-ripple-radius-bounded($query: $query);
@include mdc-feature-targets($feat-structure) {
position: relative;
outline: none;
overflow: hidden;
}
&--primary {
@include mdc-states(primary, $query: $query);
}
&--accent {
@include mdc-states(secondary, $query: $query);
}
}
}
@@ -1,79 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@import '@material/switch/mixins';
@mixin switch-core-styles($query: mdc-feature-all()) {
@include mdc-switch-core-styles($query);
.theme-switch {
@extend .mdc-switch;
}
.theme-switch_native-control {
@extend .mdc-switch__native-control;
&:disabled {
opacity: 0;
}
}
.theme-switch__track {
@extend .mdc-switch__track;
}
.theme-switch__thumb-underlay {
@extend .mdc-switch__thumb-underlay;
}
.theme-switch__thumb {
@extend .mdc-switch__thumb;
}
.theme-switch--checked {
@extend .mdc-switch--checked;
}
.theme-switch--disabled {
@extend .mdc-switch--disabled;
}
.theme-switch_dense {
@include switch-core-styles-dense($query);
}
.theme-switch_dense .theme-switch_primary,
.theme-switch_primary {
$mdc-switch-baseline-theme-color: primary;
@include mdc-switch-toggled-on-track-color($mdc-switch-baseline-theme-color, $query);
@include mdc-switch-toggled-on-thumb-color($mdc-switch-baseline-theme-color, $query);
@include mdc-switch-toggled-off-track-color($mdc-switch-toggled-off-track-color, $query);
@include mdc-switch-toggled-off-thumb-color($mdc-switch-toggled-off-thumb-color, $query);
}
}
@mixin switch-core-styles-dense($query: mdc-feature-all()) {
$mdc-switch-baseline-theme-color: primary !global;
$mdc-switch-track-width: 24px !global;
$mdc-switch-track-height: 10px !global;
$mdc-switch-thumb-diameter: 14px !global;
$mdc-switch-ripple-size: 36px !global;
$mdc-switch-toggled-off-thumb-color: lighten($mdc-switch-toggled-off-thumb-color, 5%) !global;
$mdc-switch-minimum-size: 24px !global;
$mdc-switch-maximum-size: $mdc-switch-ripple-size !global;
$mdc-switch-density-scale: $mdc-density-default-scale !global;
$mdc-switch-density-config: (
size: (
minimum: $mdc-switch-minimum-size,
default: $mdc-switch-maximum-size,
maximum: $mdc-switch-maximum-size,
),
) !global;
$mdc-switch-thumb-offset: 2px !global;
$mdc-switch-thumb-active-margin: $mdc-switch-track-width - $mdc-switch-thumb-diameter + $mdc-switch-thumb-offset * 2 !global;
@include mdc-switch-core-styles($query);
}
@@ -60,22 +60,6 @@ $mdc-theme-text-colors: (
),
);
$mdc-ripple-dark-ink-opacities: (
hover: 0.04,
focus: 0.1,
press: 0.1,
selected: 0.06,
activated: 0.1,
) !default;
$mdc-ripple-light-ink-opacities: (
hover: 0.04,
focus: 0.1,
press: 0.1,
selected: 0.06,
activated: 0.1,
) !default;
$theme-name: 'dark';
@import './mixins';
@@ -17,6 +17,7 @@ $mdc-theme-on-sub-secondary: #6d6d6d;
$mdc-theme-surface: #ffffff;
$mdc-theme-on-surface: #353535;
$mdc-theme-background: #dedede;
$mdc-theme-error: #e94948;
$color-scheme: light;
$color-positive: #52c41a;
@@ -1,114 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@mixin theme-ripple-color($query, $color) {
&.theme-ripple,
.theme-ripple {
@include mdc-states($color, $query: $query);
&[aria-expanded='true'] {
&::before {
opacity: mdc-states-opacity($color, focus) + mdc-states-opacity($color, hover);
}
}
&.theme-ripple-selectable {
&[aria-selected='true'] {
&::before {
opacity: mdc-states-opacity($color, focus) + mdc-states-opacity($color, hover);
}
}
}
}
}
@mixin theme-ripple($query: mdc-feature-all()) {
$feat-structure: mdc-feature-create-target($query, structure);
@include mdc-ripple-common($query);
&.theme-ripple,
.theme-ripple {
position: relative;
&::before {
@include mdc-ripple-surface($query);
@include mdc-ripple-radius-bounded($query: $query);
@include mdc-feature-targets($feat-structure) {
position: absolute;
content: '';
opacity: 0;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
}
&.theme-ripple-background {
@include mdc-theme-prop(background-color, background, false);
@include mdc-theme-prop(color, text-hint-on-light, false);
&.theme-ripple-selectable {
&:hover {
@include mdc-theme-prop(color, text-primary-on-light, false);
}
&[aria-selected='true'] {
@include mdc-theme-prop(background-color, surface, false);
@include mdc-theme-prop(color, text-primary-on-light, false);
&::before {
opacity: 0 !important;
}
}
}
}
&.theme-ripple-secondary {
@include mdc-theme-prop(background-color, secondary, false);
@include mdc-theme-prop(color, text-hint-on-light, false);
&.theme-ripple-selectable {
&:hover {
@include mdc-theme-prop(color, text-primary-on-light, false);
}
&[aria-selected='true'] {
@include mdc-theme-prop(background-color, surface, false);
@include mdc-theme-prop(color, text-primary-on-light, false);
&::before {
opacity: 0 !important;
}
}
}
}
&.theme-ripple-surface {
@include mdc-theme-prop(background-color, surface, false);
@include mdc-theme-prop(color, text-hint-on-light, false);
&.theme-ripple-selectable {
&:hover {
@include mdc-theme-prop(color, text-primary-on-light, false);
}
&[aria-selected='true'] {
@include mdc-theme-prop(background-color, surface, false);
@include mdc-theme-prop(color, text-primary-on-light, false);
&::before {
opacity: 0 !important;
}
}
}
}
}
}
@@ -6,28 +6,6 @@
* you may not use this file except in compliance with the License.
*/
$mdc-theme-extra-property-values: (
sub-secondary: $mdc-theme-sub-secondary,
on-sub-secondary: $mdc-theme-on-sub-secondary,
positive: $color-positive,
on-positive: $color-on-positive,
negative: $color-negative,
status: $color-status,
link-color: $link-color,
input-color: $input-color,
input-color-disabled: $input-color-disabled,
input-color-readonly: $input-color-readonly,
input-color-placeholder: $input-color-placeholder,
input-border: $input-border,
input-border-readonly: $input-border-readonly,
input-border-disabled: $input-border-disabled,
input-background: $input-background,
input-background-disabled: $input-background-disabled,
input-background-readonly: $input-background-readonly,
);
$mdc-theme-property-values: map-merge($mdc-theme-property-values, $mdc-theme-extra-property-values);
$theme-class: 'theme-#{$theme-name}';
$theme-form-element-radius: 3px !default;
$theme-group-element-radius: 4px !default;
@@ -51,6 +29,8 @@ $app-height: 100vh !default;
--theme-form-element-radius: #{$theme-form-element-radius};
--theme-group-element-radius: #{$theme-group-element-radius};
--theme-menu-bar-small-action-radius: #{$theme-menu-bar-small-action-radius};
--theme-font-family: Roboto, sans-serif;
--theme-font-family-mono: RobotoMono, sans-serif;
}
@layer components {
@@ -1,109 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@import "@material/layout-grid/variables";
@import "@material/layout-grid/mixins";
@mixin layout-grid($query: mdc-feature-all()) {
:root {
@each $size in map-keys($mdc-layout-grid-columns) {
--mdc-layout-grid-margin-#{$size}: #{map-get($mdc-layout-grid-default-margin, $size)};
--mdc-layout-grid-gutter-#{$size}: #{map-get($mdc-layout-grid-default-gutter, $size)};
--mdc-layout-grid-column-width-#{$size}: #{map-get($mdc-layout-grid-column-width, $size)};
}
}
.layout-grid {
@each $size in map-keys($mdc-layout-grid-columns) {
@include mdc-layout-grid-media-query_($size) {
$margin: map-get($mdc-layout-grid-default-margin, $size);
@include mdc-layout-grid($size, $margin, $mdc-layout-grid-max-width);
}
}
}
.layout-grid__inner {
@each $size in map-keys($mdc-layout-grid-columns) {
@include mdc-layout-grid-media-query_($size) {
$margin: map-get($mdc-layout-grid-default-margin, $size);
$gutter: map-get($mdc-layout-grid-default-gutter, $size);
@include mdc-layout-grid-inner($size, $margin, $gutter);
}
}
}
.layout-grid__cell {
// select the upper breakpoint
$upper-breakpoint: nth(map-keys($mdc-layout-grid-columns), 1);
@each $size in map-keys($mdc-layout-grid-columns) {
@include mdc-layout-grid-media-query_($size) {
$gutter: map-get($mdc-layout-grid-default-gutter, $size);
@include mdc-layout-grid-cell($size, $mdc-layout-grid-default-column-span, $gutter);
@for $span from 1 through map-get($mdc-layout-grid-columns, $upper-breakpoint) {
// Span classes.
@at-root .layout-grid__cell--span-#{$span},
.layout-grid__cell--span-#{$span}-#{$size},
.layout-grid__cell[data-span="#{$span}"],
.layout-grid__cell[data-span-#{$size}="#{$span}"] {
@include mdc-layout-grid-cell-span_($size, $span, $gutter);
}
}
}
}
// Order override classes.
@for $i from 1 through map-get($mdc-layout-grid-columns, $upper-breakpoint) {
&--order-#{$i} {
@include mdc-layout-grid-cell-order($i);
}
}
// Alignment classes.
&--align-top {
@include mdc-layout-grid-cell-align(top);
}
&--align-middle {
@include mdc-layout-grid-cell-align(middle);
}
&--align-bottom {
@include mdc-layout-grid-cell-align(bottom);
}
}
.layout-grid--fixed-column-width,
.layout-grid[data-grid-fixed-width=true] {
@each $size in map-keys($mdc-layout-grid-columns) {
@include mdc-layout-grid-media-query_($size) {
$margin: map-get($mdc-layout-grid-default-margin, $size);
$gutter: map-get($mdc-layout-grid-default-gutter, $size);
$column-width: map-get($mdc-layout-grid-column-width, $size);
@include mdc-layout-grid-fixed-column-width($size, $margin, $gutter, $column-width);
}
}
}
.layout-grid--align-left,
[data--grid-align="left"] {
margin-right: auto;
margin-left: 0;
}
.layout-grid--align-right,
[data-grid-align="right"] {
margin-right: 0;
margin-left: auto;
}
}
@@ -8,14 +8,14 @@
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.3s;
transition: opacity var(--duration-slow);
background: white;
}
#app-loading-screen .app-loading-screen__logo-spinner {
transform-origin: center;
-webkit-animation:spin 2s linear infinite;
-moz-animation:spin 2s linear infinite;
animation:spin 2s linear infinite;
-webkit-animation: spin var(--duration-spin) var(--ease-evenly) infinite;
-moz-animation: spin var(--duration-spin) var(--ease-evenly) infinite;
animation: spin var(--duration-spin) var(--ease-evenly) infinite;
}
:not(:empty) + #app-loading-screen.app-loading-screen--fade-out {
opacity: 0;
@@ -24,6 +24,19 @@
display: none;
}
@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
@-moz-keyframes spin {
100% {
-moz-transform: rotate(360deg);
}
}
@-webkit-keyframes spin {
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@@ -13,13 +13,8 @@
@include colors;
@include color-scheme;
@include css-variables;
@include ripple-core-styles;
@include theme-ripple;
@include layout-grid;
@include form-controls;
@include switch-core-styles;
@include link;
@include placeholder;
@include delimiter($mdc-theme-secondary);
@include branding-overflow;
}
@@ -1,32 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@import '@material/elevation/mixins';
@mixin elevation-core-styles($query: mdc-feature-all()) {
$feat-animation: mdc-feature-create-target($query, animation);
$feat-structure: mdc-feature-create-target($query, structure);
@for $z-value from 0 through 24 {
.theme-elevation-z#{$z-value} {
@include mdc-elevation($z-value, $query: $query);
}
}
.theme-elevation-transition {
@include mdc-feature-targets($feat-animation) {
transition: mdc-elevation-transition-value();
}
@include mdc-feature-targets($feat-structure) {
will-change: $mdc-elevation-property;
}
}
}
@include elevation-core-styles;
@@ -13,13 +13,8 @@
@include colors;
@include color-scheme;
@include css-variables;
@include ripple-core-styles;
@include theme-ripple;
@include layout-grid;
@include form-controls;
@include switch-core-styles;
@include link;
@include placeholder;
@include delimiter($mdc-theme-secondary);
@include branding-overflow;
}
@@ -1,23 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@import '@material/typography/mixins';
@mixin typography-core-styles($query: mdc-feature-all()) {
.theme-typography {
@include mdc-typography-base($query: $query);
}
@each $style in map-keys($mdc-typography-styles) {
.theme-typography--#{$style} {
@include mdc-typography($style, $query: $query);
}
}
}
@include typography-core-styles;
@@ -9,13 +9,8 @@
@import './theme-dark';
@include theme-matcher;
@include layout-grid;
@include colors;
@include ripple-core-styles;
@include theme-ripple;
@include switch-core-styles;
@include form-controls;
@include link;
@include placeholder;
@include delimiter($mdc-theme-background);
@include branding-overflow;
@@ -9,13 +9,8 @@
@import './theme-light';
@include theme-matcher;
@include layout-grid;
@include colors;
@include ripple-core-styles;
@include theme-ripple;
@include switch-core-styles;
@include form-controls;
@include link;
@include placeholder;
@include delimiter($mdc-theme-background);
@include branding-overflow;
@@ -60,6 +60,7 @@
display: none;
& .icon {
fill: var(--theme-on-primary);
width: 12px;
}
}
@@ -6,10 +6,6 @@
* you may not use this file except in compliance with the License.
*/
.placeholder {
composes: placeholder from global;
}
.tab {
position: relative;
font-weight: normal;
@@ -1,17 +1,21 @@
.layoutGrid {
composes: layout-grid from global;
display: grid;
box-sizing: border-box;
width: 100%;
flex: 1;
padding: 24px;
}
.layoutGridInner {
composes: layout-grid__inner from global;
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 24px;
min-height: 100%;
}
.layoutGridCell {
composes: layout-grid__cell from global;
composes: theme-background-surface theme-text-on-surface theme-border-color-background from global;
grid-column: 1 / -1;
position: relative;
border: solid 1px;
padding: 16px 24px;
@@ -27,6 +27,7 @@
"@cloudbeaver/core-localization": "workspace:*",
"@cloudbeaver/core-theming": "workspace:*",
"@cloudbeaver/core-utils": "workspace:*",
"@cloudbeaver/plugin-tailwindcss-theme": "workspace:*",
"@codemirror/autocomplete": "^6",
"@codemirror/commands": "^6",
"@codemirror/lang-html": "^6",
@@ -1,46 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@mixin base-code-editor-autocompletion() {
.cm-tooltip.cm-tooltip-autocomplete {
&>:global(ul) {
border-radius: var(--theme-form-element-radius);
}
& :global(li) {
display: flex;
align-items: center;
}
& .cm-completionIcon {
opacity: 1;
width: 16px;
height: 16px;
padding: 0;
margin-right: .6em;
&:not(:global([src])) {
opacity: 0;
}
}
& :global(li):hover {
@include mdc-theme-prop(background, sub-secondary, false);
@include mdc-theme-prop(color, on-secondary, false);
}
& :global(li):global([aria-selected=true]) {
@include mdc-theme-prop(background, secondary, false);
@include mdc-theme-prop(color, text-primary-on-light, false);
}
}
.cm-tooltip.cm-completionInfo {
margin-left: 8px;
}
}
@@ -1,18 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@mixin base-code-editor-tooltip() {
.cm-tooltip {
@include mdc-theme-prop(background-color, surface, false);
@include mdc-theme-prop(color, on-surface, false);
@include mdc-elevation(3);
@include mdc-typography(body2);
border: none;
border-radius: var(--theme-form-element-radius);
}
}
@@ -1,339 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@mixin base-code-editor() {
.editor,
.cm-editor,
.cm-mergeView,
.cm-mergeViewEditors,
.cm-scroller,
.ReactCodemirror {
width: 100%;
height: 100% !important;
}
.editor,
.ReactCodemirror,
.cm-mergeView,
.cm-mergeViewEditors,
.cm-editor,
.cm-gotoLine {
@include mdc-typography('body2');
}
.cm-mergeViewEditor:first-child {
border-right: 1px solid;
@include mdc-theme-prop(border-color, background, false);
}
.editor .cm-highlightTab {
opacity: 0.6;
color: var(--theme-text-hint-on-light);
pointer-events: none;
}
.editor .cm-newline {
color: var(--theme-text-hint-on-light);
opacity: 0.6;
margin-left: 4px;
cursor: default;
pointer-events: none;
}
.editor .cm-highlightSpace {
background-image: radial-gradient(circle at 50% 55%, var(--theme-text-hint-on-light) 15%, transparent 5%);
opacity: 0.6;
background-position: center;
}
.editor {
@include mdc-theme-prop(background-color, surface, false);
@include mdc-theme-prop(color, on-surface, false);
}
.editor .cm-scroller {
outline: none;
line-height: unset;
}
.editor .cm-content {
caret-color: $cursor;
}
.editor .cm-cursor {
border-left-color: $cursor;
}
.editor .cm-link {
&.cm-link-loaded {
@include mdc-theme-prop(color, primary, false);
text-decoration: underline;
cursor: pointer;
}
}
.editor .cm-dropCursor {
border-left: 1.2px solid $cursor;
}
.editor .cm-gutters,
.cm-panel {
@include mdc-theme-prop(background-color, surface, false);
@include mdc-theme-prop(color, text-hint-on-light, false);
@include mdc-theme-prop(border-color, background, false);
}
.cm-panels-top,
.cm-panels-bottom {
@include mdc-theme-prop(border-color, background, false);
}
.editor .cm-activeLine {
box-shadow: 0 0 0 2px $mdc-theme-sub-secondary;
}
.editor .cm-activeLineGutter {
@include mdc-theme-prop(color, on-surface, false);
}
.ͼ2 .cm-activeLine:not(.cm-changedLine, .cm-deletedLine),
.ͼ2 .cm-activeLineGutter:not(.cm-changedLineGutter, .cm-deletedLineGutter) {
background-color: unset;
}
.editor .active-query {
/* disable because look too ugly */
/*
display: inline-block;
@include mdc-theme-prop(background, secondary, false);
*/
}
.editor .cm-gotoLine.cm-panel {
display: flex;
align-items: flex-end;
flex-wrap: wrap;
padding: 4px 8px;
gap: 8px;
min-width: 160px;
container-type: inline-size;
& label {
display: flex;
flex-wrap: wrap;
align-items: center;
text-transform: uppercase;
letter-spacing: -0.1px;
gap: 4px;
}
& input {
@include mdc-typography('body2');
max-width: 60px;
height: 24px;
padding-inline: 8px;
&:focus {
@include mdc-theme-prop(border-color, primary, false);
}
}
& .cm-button {
@include mdc-typography('body2');
background: transparent;
height: 24px;
padding-block: 0;
margin-right: 24px;
font-weight: 500;
text-transform: uppercase;
color: var(--theme-primary);
border-radius: 4px;
border-color: var(--theme-primary);
&:hover {
background: color-mix(in srgb, transparent, var(--theme-primary) 5%);
}
@container (width < 240px) {
display: none;
}
}
& button[name='close'] {
margin-left: auto;
padding: 0 8px;
top: 4px;
height: 24px;
width: 24px;
border-radius: 4px;
background: transparent;
color: var(--theme-on-surface);
border-color: var(--theme-on-surface);
font-size: 16px;
&:hover {
background: color-mix(in srgb, transparent, var(--theme-on-surface) 5%);
}
}
}
.editor .cm-content ::selection {
@include mdc-theme-prop(background, primary, false);
color: white;
}
.editor .cm-lineNumbers .cm-gutterElement {
min-width: 3ch;
box-sizing: content-box;
}
.editor .cm-gutters .cm-foldGutter .cm-gutterElement {
display: flex;
align-items: center;
cursor: pointer;
user-select: none;
}
.editor .cm-gutters .cm-foldGutter .cm-gutterElement-icon {
padding: 0 3px 0 5px;
width: 20px;
height: 12px;
display: flex;
&.cm-foldGutter-folded :global(svg) {
transform: rotate(-90deg);
}
}
.editor .cm-gutters .query-status .cm-gutterElement {
display: flex;
align-items: center;
justify-content: center;
width: 14px;
.running-query-line {
display: flex;
height: 8px;
width: 8px;
border-radius: 100%;
@include mdc-theme-prop(background, primary, false);
}
.running-query-error-line {
display: flex;
height: 8px;
width: 8px;
border-radius: 100%;
@include mdc-theme-prop(background, negative, false);
}
}
.editor .tok-keyword {
color: $keyword;
font-weight: bold;
}
.editor .tok-operator {
color: $operator;
}
.editor .tok-variable-2 {
color: $variable-2;
}
.editor .tok-variable-3,
.editor .tok-type {
color: $variable-3;
}
.editor .tok-builtin {
color: $builtin;
}
.editor .tok-atom {
color: $atom;
}
.editor .tok-number {
color: $number;
}
.editor .tok-def {
color: $def;
}
.editor .tok-string {
color: $string;
}
.editor .tok-string2 {
color: $string-2;
}
.editor .tok-comment {
color: $comment;
}
.editor .tok-variable {
color: $variable;
}
.editor .tok-tag {
color: $tag;
}
.editor .tok-meta {
color: $meta;
}
.editor .tok-attribute {
color: $attribute;
}
.editor .tok-property {
color: $property;
}
.editor .tok-qualifier {
color: $qualifier;
}
.editor .tok-variable-3,
.editor .tok-type {
color: $variable-3;
}
.editor .tok-typeName {
color: $type-name;
}
.editor .tok-punctuation {
color: $punctuation;
}
.editor .tok-propertyName {
color: $property-name;
}
.editor .tok-className {
color: $class-name;
}
.editor .tok-bool {
color: $bool;
}
.editor .tok-variableName {
color: $variable-name;
}
.editor .tok-labelName {
color: $label-name;
}
}
@@ -0,0 +1,39 @@
/* Increase specificity by selector repetition */
.cm-tooltip.cm-tooltip {
&.cm-tooltip-autocomplete {
& > ul {
border-radius: var(--theme-form-element-radius);
}
& li {
display: flex;
align-items: center;
&:hover {
background: var(--theme-sub-secondary);
color: var(--theme-on-secondary);
}
&[aria-selected='true'] {
background: var(--theme-secondary);
color: var(--theme-text-primary-on-light);
}
}
& .cm-completionIcon {
opacity: 1;
width: 16px;
height: 16px;
padding: 0;
margin-right: 0.6em;
&:not([src]) {
opacity: 0;
}
}
}
&.cm-completionInfo {
margin-left: 8px;
}
}
@@ -0,0 +1,14 @@
@import '@cloudbeaver/plugin-tailwindcss-theme/tailwind.css';
/* Increase specificity by selector repetition */
.cm-tooltip.cm-tooltip {
@apply tw:typography-body2;
box-shadow:
0px 3px 3px -2px rgba(0, 0, 0, 0.2),
0px 3px 4px 0px rgba(0, 0, 0, 0.14),
0px 1px 8px 0px rgba(0, 0, 0, 0.12);
background-color: var(--theme-surface);
color: var(--theme-on-surface);
border: none;
border-radius: var(--theme-form-element-radius);
}
@@ -0,0 +1,327 @@
@import '@cloudbeaver/plugin-tailwindcss-theme/tailwind.css';
/* Increase specificity by selector repetition */
.editor.editor,
.cm-editor.cm-editor,
.cm-mergeView.cm-mergeView,
.cm-mergeViewEditors.cm-mergeViewEditors,
.cm-scroller.cm-scroller,
.ReactCodemirror.ReactCodemirror {
width: 100%;
height: 100% !important;
}
.editor.editor,
.ReactCodemirror.ReactCodemirror,
.cm-mergeView.cm-mergeView,
.cm-mergeViewEditors.cm-mergeViewEditors,
.cm-editor.cm-editor,
.cm-gotoLine.cm-gotoLine {
@apply tw:typography-body2;
}
.cm-mergeViewEditor.cm-mergeViewEditor {
&:first-child {
border-right: 1px solid;
border-color: var(--theme-background);
}
}
.editor.editor {
background-color: var(--theme-surface);
color: var(--theme-on-surface);
& .cm-highlightTab {
opacity: 0.6;
color: var(--theme-text-hint-on-light);
pointer-events: none;
}
& .cm-newline {
color: var(--theme-text-hint-on-light);
opacity: 0.6;
margin-left: 4px;
cursor: default;
pointer-events: none;
}
& .cm-highlightSpace {
background-image: radial-gradient(circle at 50% 55%, var(--theme-text-hint-on-light) 15%, transparent 5%);
opacity: 0.6;
background-position: center;
}
& .cm-scroller {
outline: none;
line-height: unset;
}
& .cm-content {
caret-color: var(--editor-cursor);
}
& .cm-cursor {
border-left-color: var(--editor-cursor);
}
& .cm-link {
&.cm-link-loaded {
color: var(--theme-primary);
text-decoration: underline;
cursor: pointer;
}
}
& .cm-dropCursor {
border-left: 1.2px solid var(--editor-cursor);
}
& .cm-gutters {
background-color: var(--theme-surface);
color: var(--theme-text-hint-on-light);
border-color: var(--theme-background);
}
& .cm-activeLine {
box-shadow: 0 0 0 2px var(--theme-sub-secondary);
}
& .cm-activeLineGutter {
color: var(--theme-on-surface);
}
& .cm-gotoLine.cm-panel {
display: flex;
align-items: flex-end;
flex-wrap: wrap;
padding: 4px 8px;
gap: 8px;
min-width: 160px;
container-type: inline-size;
& label {
display: flex;
flex-wrap: wrap;
align-items: center;
text-transform: uppercase;
letter-spacing: -0.1px;
gap: 4px;
}
& input {
@apply tw:typography-body2;
max-width: 60px;
height: 24px;
padding-inline: 8px;
&:focus {
border-color: var(--theme-primary);
}
}
& .cm-button {
@apply tw:typography-body2;
background: transparent;
height: 24px;
padding-block: 0;
margin-right: 24px;
font-weight: 500;
text-transform: uppercase;
color: var(--theme-primary);
border-radius: 4px;
border-color: var(--theme-primary);
&:hover {
background: color-mix(in srgb, transparent, var(--theme-primary) 5%);
}
@container (width < 240px) {
display: none;
}
}
& button[name='close'] {
margin-left: auto;
padding: 0 8px;
top: 4px;
height: 24px;
width: 24px;
border-radius: 4px;
background: transparent;
color: var(--theme-on-surface);
border-color: var(--theme-on-surface);
font-size: 16px;
&:hover {
background: color-mix(in srgb, transparent, var(--theme-on-surface) 5%);
}
}
}
& .cm-content ::selection {
background: var(--theme-primary);
color: white;
}
& .cm-lineNumbers .cm-gutterElement {
min-width: 3ch;
box-sizing: content-box;
}
& .cm-gutters .cm-foldGutter .cm-gutterElement {
display: flex;
align-items: center;
cursor: pointer;
user-select: none;
}
& .cm-gutters .cm-foldGutter .cm-gutterElement-icon {
padding: 0 3px 0 5px;
width: 20px;
height: 12px;
display: flex;
&.cm-foldGutter-folded svg {
transform: rotate(-90deg);
}
}
& .cm-gutters .query-status .cm-gutterElement {
display: flex;
align-items: center;
justify-content: center;
width: 14px;
.running-query-line {
display: flex;
height: 8px;
width: 8px;
border-radius: 100%;
background: var(--theme-primary);
}
.running-query-error-line {
display: flex;
height: 8px;
width: 8px;
border-radius: 100%;
background: var(--theme-negative);
}
}
& .tok-keyword {
color: var(--editor-keyword);
font-weight: bold;
}
& .tok-operator {
color: var(--editor-operator);
}
& .tok-variable-2 {
color: var(--editor-variable-2);
}
& .tok-variable-3,
& .tok-type {
color: var(--editor-variable-3);
}
& .tok-builtin {
color: var(--editor-builtin);
}
& .tok-atom {
color: var(--editor-atom);
}
& .tok-number {
color: var(--editor-number);
}
& .tok-def {
color: var(--editor-def);
}
& .tok-string {
color: var(--editor-string);
}
& .tok-string2 {
color: var(--editor-string-2);
}
& .tok-comment {
color: var(--editor-comment);
}
& .tok-variable {
color: var(--editor-variable);
}
& .tok-tag {
color: var(--editor-tag);
}
& .tok-meta {
color: var(--editor-meta);
}
& .tok-attribute {
color: var(--editor-attribute);
}
& .tok-property {
color: var(--editor-property);
}
& .tok-qualifier {
color: var(--editor-qualifier);
}
& .tok-typeName {
color: var(--editor-type-name);
}
& .tok-punctuation {
color: var(--editor-punctuation);
}
& .tok-propertyName {
color: var(--editor-property-name);
}
& .tok-className {
color: var(--editor-class-name);
}
& .tok-bool {
color: var(--editor-bool);
}
& .tok-variableName {
color: var(--editor-variable-name);
}
& .tok-labelName {
color: var(--editor-label-name);
}
}
.cm-panel.cm-panel {
background-color: var(--theme-surface);
color: var(--theme-text-hint-on-light);
border-color: var(--theme-background);
}
.cm-panels-top.cm-panels-top,
.cm-panels-bottom.cm-panels-bottom {
border-color: var(--theme-background) !important;
}
.ͼ2.ͼ2 {
& .cm-activeLine:not(.cm-changedLine, .cm-deletedLine),
& .cm-activeLineGutter:not(.cm-changedLineGutter, .cm-deletedLineGutter) {
background-color: unset;
}
}
@@ -0,0 +1,31 @@
.theme-dark {
--editor-meta: #ff1717;
--editor-keyword: rgb(115, 158, 202);
--editor-atom: #56c8d8;
--editor-number: rgb(192, 192, 192);
--editor-def: #00f;
--editor-variable: rgb(126, 186, 211);
--editor-variable-2: rgb(193, 170, 108);
--editor-variable-3: rgb(193, 170, 108);
--editor-property: rgb(126, 186, 211);
--editor-operator: rgb(126, 186, 211);
--editor-comment: rgb(102, 151, 104);
--editor-string: rgb(202, 197, 128);
--editor-string-2: #f50;
--editor-qualifier: #555;
--editor-builtin: #ab87ff;
--editor-bracket: #cc7;
--editor-tag: #170;
--editor-attribute: #00c;
--editor-link: #219;
--editor-error: #f00;
--editor-delimiter: rgb(238, 204, 100);
--editor-cursor: #fff;
--editor-type-name: #c586c0;
--editor-class-name: #c586c0;
--editor-punctuation: #ffffff8c;
--editor-property-name: #569cd6;
--editor-bool: #56c8d8;
--editor-variable-name: #56c8d8;
--editor-label-name: #cf6edf;
}
@@ -1,49 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@import '@cloudbeaver/core-theming/src/styles/theme-dark';
@import './base-code-editor';
@import './base-code-editor-autocompletion';
@import './base-code-editor-tooltip';
$meta: #ff1717;
$keyword: rgb(115, 158, 202);
$atom: #56c8d8;
$number: rgb(192, 192, 192);
$def: #00f;
$variable: rgb(126, 186, 211);
$variable-2: rgb(193, 170, 108);
$variable-3: rgb(193, 170, 108);
$property: rgb(126, 186, 211);
$operator: rgb(126, 186, 211);
$comment: rgb(102, 151, 104);
$string: rgb(202, 197, 128);
$string-2: #f50;
$qualifier: #555;
$builtin: #ab87ff;
$bracket: #cc7;
$tag: #170;
$attribute: #00c;
$link: #219;
$error: #f00;
$delimiter: rgb(238, 204, 100);
$cursor: #fff;
$active-query: $color-positive;
$type-name: #c586c0;
$class-name: #c586c0;
$punctuation: #ffffff8c;
$property-name: #569cd6;
$bool: #56c8d8;
$variable-name: #56c8d8;
$label-name: #cf6edf;
:global .#{$theme-class} {
@include base-code-editor;
@include base-code-editor-autocompletion;
@include base-code-editor-tooltip;
}
@@ -0,0 +1,31 @@
.theme-light {
--editor-meta: #ff1717;
--editor-keyword: #07a;
--editor-atom: #905;
--editor-number: #905;
--editor-def: #00f;
--editor-variable: black;
--editor-variable-2: #a8bd00;
--editor-variable-3: #a8bd00;
--editor-property: black;
--editor-operator: #a67f59;
--editor-comment: #3f7f5f;
--editor-string: #1f8900;
--editor-string-2: #f50;
--editor-qualifier: #555;
--editor-builtin: #07a;
--editor-bracket: #cc7;
--editor-tag: #170;
--editor-attribute: #00c;
--editor-link: #905;
--editor-error: #f00;
--editor-delimiter: rgb(238, 204, 100);
--editor-cursor: #000;
--editor-type-name: #007acc;
--editor-class-name: #007acc;
--editor-punctuation: #6d6d6d;
--editor-property-name: #c42626;
--editor-bool: #905;
--editor-variable-name: #905;
--editor-label-name: #81a1c1;
}
@@ -1,49 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
@import '@cloudbeaver/core-theming/src/styles/theme-light';
@import './base-code-editor';
@import './base-code-editor-autocompletion';
@import './base-code-editor-tooltip';
$meta: #ff1717;
$keyword: #07a;
$atom: #905;
$number: #905;
$def: #00f;
$variable: black;
$variable-2: #a8bd00;
$variable-3: #a8bd00;
$property: black;
$operator: #a67f59;
$comment: #3f7f5f;
$string: #1f8900;
$string-2: #f50;
$qualifier: #555;
$builtin: #07a;
$bracket: #cc7;
$tag: #170;
$attribute: #00c;
$link: #905;
$error: #f00;
$delimiter: rgb(238, 204, 100);
$cursor: #000;
$active-query: $color-positive;
$type-name: #007acc;
$class-name: #007acc;
$punctuation: #6d6d6d;
$property-name: #c42626;
$bool: #905;
$variable-name: #905;
$label-name: #81a1c1;
:global .#{$theme-class} {
@include base-code-editor;
@include base-code-editor-autocompletion;
@include base-code-editor-tooltip;
}
@@ -1,24 +1,24 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import type { ThemeSelector } from '@cloudbeaver/core-theming';
import type Dark from './dark.module.scss';
import type Light from './light.module.scss';
import './base-code-editor.css';
import './base-code-editor-autocompletion.css';
import './base-code-editor-tooltip.css';
export const EDITOR_BASE_STYLES: ThemeSelector = async theme => {
let styles: typeof Light & typeof Dark;
let styles: any;
switch (theme) {
case 'dark':
styles = (await import('./dark.module.scss')).default;
styles = (await import('./dark.css')).default;
break;
default:
styles = (await import('./light.module.scss')).default;
styles = (await import('./light.css')).default;
break;
}
@@ -27,6 +27,9 @@
},
{
"path": "../core-utils"
},
{
"path": "../plugin-tailwindcss-theme"
}
],
"include": [
@@ -61,7 +61,7 @@ export const ConnectionPreferencesForm = observer<ConnectionPreferencesFormProps
<div className="tw:flex tw:flex-col tw:flex-1 tw:h-full tw:overflow-auto theme-background-secondary theme-text-on-secondary">
<div className="tw:relative tw:flex tw:pt-4 tw:border-b-2 theme-border-color-background theme-background-secondary theme-text-on-secondary">
<div className="tw:flex-1 tw:overflow-hidden">
<div className="tw:h-6 tw:px-4 tw:flex tw:items-center tw:gap-2 theme-typography-caption tw:overflow-hidden">
<div className="tw:h-6 tw:px-4 tw:flex tw:items-center tw:gap-2 theme-typography--caption tw:overflow-hidden">
<StatusMessage
type={exception ? ENotificationType.Error : ENotificationType.Info}
message={formState.statusMessage}
@@ -20,10 +20,10 @@
z-index: 1;
opacity: 0;
transition:
opacity 0.3s ease-in-out,
width 0.3s ease-in-out,
height 0.3s ease-in-out,
background 0.3s ease-in-out;
opacity var(--duration-slow) var(--ease-smooth),
width var(--duration-slow) var(--ease-smooth),
height var(--duration-slow) var(--ease-smooth),
background var(--duration-slow) var(--ease-smooth);
}
.errorBody {
display: flex;
@@ -5,6 +5,7 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
button.holidayButton {
height: 48px;
width: 48px;
@@ -14,8 +15,8 @@ button.holidayButton {
.holidayButton img {
transition:
filter 0.3s,
transform 0.3s ease-in-out;
filter var(--duration-slow),
transform var(--duration-slow) var(--ease-smooth);
}
.holidayButton:hover {
@@ -5,8 +5,9 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.treeNodeControl {
transition: opacity 0.3s ease;
transition: opacity var(--duration-slow) var(--ease-soft);
opacity: 1;
&.outdated {
@@ -5,16 +5,17 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.iconButton {
& .icon,
& .staticImage {
transition: transform 0.3s ease-in-out;
transition: transform var(--duration-slow) var(--ease-smooth);
}
&.loading {
& .icon,
& .staticImage {
animation: rotating 1.5s linear infinite;
animation: rotating var(--duration-spin) var(--ease-evenly) infinite;
}
}
@@ -5,8 +5,9 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.control {
transition: opacity 0.3s ease;
transition: opacity var(--duration-slow) var(--ease-soft);
opacity: 1;
&.outdated {
@@ -5,8 +5,9 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
.treeNodeControl {
transition: opacity 0.3s ease;
transition: opacity var(--duration-slow) var(--ease-soft);
opacity: 1;
&.outdated {
@@ -13,7 +13,7 @@
cursor: pointer;
opacity: 0.5;
transform: rotate(-90deg);
transition: transform 0.15s ease-in-out;
transition: transform var(--duration-medium) var(--ease-smooth);
&.expanded {
transform: rotate(0deg);
@@ -0,0 +1,39 @@
{
"name": "@cloudbeaver/plugin-tailwindcss-theme",
"type": "module",
"sideEffects": [
"./lib/module.js",
"./lib/index.js",
"src/**/*.css",
"src/**/*.scss",
"public/**/*"
],
"version": "0.1.0",
"description": "",
"license": "Apache-2.0",
"exports": {
".": "./lib/index.js",
"./module": "./lib/module.js",
"./tailwind.css": "./src/styles/index.css",
"./*": "./*"
},
"scripts": {
"build": "tsc -b",
"clean": "rimraf --glob lib",
"lint": "eslint ./src/ --ext .ts,.tsx",
"test": "dbeaver-test",
"validate-dependencies": "core-cli-validate-dependencies"
},
"dependencies": {
"@cloudbeaver/core-di": "workspace:*",
"tailwindcss": "4.0.7"
},
"devDependencies": {
"@cloudbeaver/core-cli": "workspace:*",
"@cloudbeaver/tsconfig": "workspace:*",
"@dbeaver/cli": "workspace:*",
"rimraf": "^6",
"tslib": "^2",
"typescript": "^5"
}
}
@@ -0,0 +1,55 @@
:root {
--duration-fast: 100ms;
--duration-medium: 200ms;
--duration-slow: 350ms;
--duration-slowest: 500ms;
--duration-spin: 1.5s;
--ease-evenly: linear;
--ease-soft: ease;
--ease-smooth: ease-in-out;
--ease-smooth-end: cubic-bezier(0, 0, 0.2, 1);
--ease-smooth-start: cubic-bezier(0.4, 0, 0.2, 1);
--ease-emphasized: cubic-bezier(0.4, 0, 0.6, 1);
}
@utility duration-fast {
transition-duration: var(--duration-fast);
}
@utility duration-medium {
transition-duration: var(--duration-medium);
}
@utility duration-slow {
transition-duration: var(--duration-slow);
}
@utility duration-slowest {
transition-duration: var(--duration-slowest);
}
@utility ease-evenly {
transition-timing-function: var(--ease-evenly);
}
@utility ease-soft {
transition-timing-function: var(--ease-soft);
}
@utility ease-smooth {
transition-timing-function: var(--ease-smooth);
}
@utility ease-smooth-end {
transition-timing-function: var(--ease-smooth-end);
}
@utility ease-smooth-start {
transition-timing-function: var(--ease-smooth-start);
}
@utility ease-emphasized {
transition-timing-function: var(--ease-emphasized);
}
@@ -0,0 +1,8 @@
@import 'tailwindcss' layer(base) prefix(tw);
@import './animation.css';
@import './shadow.css';
@import './typography.css';
@import './typography-utilities.css';
@import './ripple.css';
@custom-variant dark (&:where(.theme-dark, .theme-dark *));
@@ -0,0 +1,38 @@
/**
* Ripple Effect Utilities
*
* Provides hover/focus/active feedback using a pseudo-element overlay.
* Uses currentColor so it adapts to the parent's text color.
*/
@layer components {
.theme-ripple {
@apply tw:relative;
&::before {
@apply tw:absolute tw:content-[''] tw:opacity-0 tw:top-0 tw:left-0 tw:w-full tw:h-full tw:overflow-hidden tw:bg-[currentColor] tw:rounded-[inherit] tw:pointer-events-none;
}
&:hover::before {
opacity: 0.04;
}
&:focus::before {
opacity: 0.11;
}
&:active::before {
opacity: 0.11;
}
&[aria-expanded='true']::before {
opacity: 0.15;
}
}
.theme-ripple-selectable {
&[aria-selected='true']::before {
opacity: 0.15;
}
}
}
@@ -0,0 +1,6 @@
@theme {
--shadow-small: 0px 3px 3px -2px rgba(0, 0, 0, 0.2), 0px 3px 4px 0px rgba(0, 0, 0, 0.14), 0px 1px 8px 0px rgba(0, 0, 0, 0.12);
--shadow-medium: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 5px 8px 0px rgba(0, 0, 0, 0.14), 0px 1px 14px 0px rgba(0, 0, 0, 0.12);
--shadow-large: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 0px 1px 18px 0px rgba(0, 0, 0, 0.12);
--shadow-xlarge: 0px 6px 6px -3px rgba(0, 0, 0, 0.2), 0px 10px 14px 1px rgba(0, 0, 0, 0.14), 0px 4px 18px 3px rgba(0, 0, 0, 0.12);
}
@@ -0,0 +1,86 @@
@import './typography.css';
/* Typography utilities – usable via @apply tw:typography-body1 etc. */
@utility typography-base {
@apply tw:font-roboto tw:antialiased;
}
/* Headline 6 - 1.25rem (20px) */
@utility typography-headline6 {
@apply tw:font-roboto tw:antialiased tw:text-headline6 tw:leading-headline6 tw:font-headline6 tw:tracking-headline6 tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
/* Subtitle 1 - 1rem (16px) */
@utility typography-subtitle1 {
@apply tw:font-roboto tw:antialiased tw:text-subtitle1 tw:leading-subtitle1 tw:font-subtitle1 tw:tracking-subtitle1 tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
/* Subtitle 2 - 0.875rem (14px) */
@utility typography-subtitle2 {
@apply tw:font-roboto tw:antialiased tw:text-subtitle2 tw:leading-subtitle2 tw:font-subtitle2 tw:tracking-subtitle2 tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
/* Body 1 - 1rem (16px) */
@utility typography-body1 {
@apply tw:font-roboto tw:antialiased tw:text-body1 tw:leading-body1 tw:font-body1 tw:tracking-body1 tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
/* Body 2 - 0.875rem (14px) */
@utility typography-body2 {
@apply tw:font-roboto tw:antialiased tw:text-body2 tw:leading-body2 tw:font-body2 tw:tracking-body2 tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
/* Caption - 0.75rem (12px) */
@utility typography-caption {
@apply tw:font-roboto tw:antialiased tw:text-caption tw:leading-caption tw:font-caption tw:tracking-caption tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
/* Button - 0.875rem (14px) */
@utility typography-button {
@apply tw:font-roboto tw:antialiased tw:text-button tw:leading-button tw:font-button tw:tracking-button tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
/* Overline - 0.75rem (12px) */
@utility typography-overline {
@apply tw:font-roboto tw:antialiased tw:text-overline tw:leading-overline tw:font-overline tw:tracking-overline tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
/* Component class aliases – reuse the utilities above */
@layer components {
.theme-typography {
@apply tw:font-roboto tw:antialiased;
}
.theme-typography--headline6 {
@apply tw:font-roboto tw:antialiased tw:text-headline6 tw:leading-headline6 tw:font-headline6 tw:tracking-headline6 tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
.theme-typography--subtitle1 {
@apply tw:font-roboto tw:antialiased tw:text-subtitle1 tw:leading-subtitle1 tw:font-subtitle1 tw:tracking-subtitle1 tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
.theme-typography--subtitle2 {
@apply tw:font-roboto tw:antialiased tw:text-subtitle2 tw:leading-subtitle2 tw:font-subtitle2 tw:tracking-subtitle2 tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
.theme-typography--body1 {
@apply tw:font-roboto tw:antialiased tw:text-body1 tw:leading-body1 tw:font-body1 tw:tracking-body1 tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
.theme-typography--body2 {
@apply tw:font-roboto tw:antialiased tw:text-body2 tw:leading-body2 tw:font-body2 tw:tracking-body2 tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
.theme-typography--caption {
@apply tw:font-roboto tw:antialiased tw:text-caption tw:leading-caption tw:font-caption tw:tracking-caption tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
.theme-typography--button {
@apply tw:font-roboto tw:antialiased tw:text-button tw:leading-button tw:font-button tw:tracking-button tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
.theme-typography--overline {
@apply tw:font-roboto tw:antialiased tw:text-overline tw:leading-overline tw:font-overline tw:tracking-overline tw:[text-decoration:inherit] tw:[text-transform:inherit];
}
}
@@ -0,0 +1,53 @@
@theme {
/* Font families */
--font-roboto: Roboto, sans-serif;
--font-roboto-mono: RobotoMono, sans-serif;
/* Headline 6 – 1.25rem (20px) */
--text-headline6: 1.25rem;
--leading-headline6: 2rem;
--font-weight-headline6: 500;
--tracking-headline6: 0.0125em;
/* Subtitle 1 – 1rem (16px) */
--text-subtitle1: 1rem;
--leading-subtitle1: 1.75rem;
--font-weight-subtitle1: 400;
--tracking-subtitle1: 0.009375em;
/* Subtitle 2 – 0.875rem (14px) */
--text-subtitle2: 0.875rem;
--leading-subtitle2: 1.375rem;
--font-weight-subtitle2: 500;
--tracking-subtitle2: 0.0071428571em;
/* Body 1 – 1rem (16px) */
--text-body1: 1rem;
--leading-body1: 1.5rem;
--font-weight-body1: 400;
--tracking-body1: 0.03125em;
/* Body 2 – 0.875rem (14px) */
--text-body2: 0.875rem;
--leading-body2: 1.25rem;
--font-weight-body2: 400;
--tracking-body2: 0.0178571429em;
/* Caption – 0.75rem (12px) */
--text-caption: 0.75rem;
--leading-caption: 1.25rem;
--font-weight-caption: 400;
--tracking-caption: 0.0333333333em;
/* Button – 0.875rem (14px) */
--text-button: 0.875rem;
--leading-button: 2.25rem;
--font-weight-button: 500;
--tracking-button: 0.0892857143em;
/* Overline – 0.75rem (12px) */
--text-overline: 0.75rem;
--leading-overline: 2rem;
--font-weight-overline: 500;
--tracking-overline: 0.1666666667em;
}
@@ -0,0 +1,34 @@
{
"extends": "@cloudbeaver/tsconfig/tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib",
"tsBuildInfoFile": "lib/tsconfig.tsbuildinfo",
"composite": true
},
"references": [
{
"path": "../../common-typescript/@dbeaver/cli"
},
{
"path": "../core-cli"
},
{
"path": "../core-di"
},
{
"path": "../core-di/tsconfig.json"
}
],
"include": [
"__custom_mocks__/**/*",
"src/**/*",
"src/**/*.json",
"src/**/*.css",
"src/**/*.scss"
],
"exclude": [
"**/node_modules",
"lib/**/*"
]
}
@@ -10,6 +10,7 @@
padding: 0;
& .icon {
fill: var(--theme-on-primary);
width: 32px;
height: 100%;
padding: 0 8px;
@@ -30,6 +30,7 @@
"dependencies": {
"@cloudbeaver/core-browser": "workspace:*",
"@cloudbeaver/plugin-sso": "workspace:*",
"@cloudbeaver/plugin-tailwindcss-theme": "workspace:*",
"@cloudbeaver/product-base": "workspace:*",
"@cloudbeaver/product-default-impl": "workspace:*",
"react": "^19",
@@ -1,2 +1 @@
@import 'tailwindcss' layer(base) prefix(tw);
@custom-variant dark (&:where(.theme-dark, .theme-dark *));
@import '@cloudbeaver/plugin-tailwindcss-theme/tailwind.css';
@@ -16,6 +16,9 @@
{
"path": "../plugin-sso"
},
{
"path": "../plugin-tailwindcss-theme"
},
{
"path": "../product-base"
},
+18 -212
View File
@@ -2197,15 +2197,6 @@ __metadata:
"@dbeaver/react-tests": "workspace:*"
"@dbeaver/ui-kit": "workspace:^"
"@fontsource/roboto": "npm:^5"
"@material/button": "npm:^4"
"@material/checkbox": "npm:^4"
"@material/elevation": "npm:^4"
"@material/layout-grid": "npm:^4"
"@material/radio": "npm:^4"
"@material/ripple": "npm:^4"
"@material/switch": "npm:^4"
"@material/theme": "npm:^4"
"@material/typography": "npm:^4"
mobx: "npm:^6"
rimraf: "npm:^6"
tslib: "npm:^2"
@@ -2583,6 +2574,7 @@ __metadata:
"@cloudbeaver/core-localization": "workspace:*"
"@cloudbeaver/core-theming": "workspace:*"
"@cloudbeaver/core-utils": "workspace:*"
"@cloudbeaver/plugin-tailwindcss-theme": "workspace:*"
"@cloudbeaver/tsconfig": "workspace:*"
"@codemirror/autocomplete": "npm:^6"
"@codemirror/commands": "npm:^6"
@@ -4383,6 +4375,21 @@ __metadata:
languageName: unknown
linkType: soft
"@cloudbeaver/plugin-tailwindcss-theme@workspace:*, @cloudbeaver/plugin-tailwindcss-theme@workspace:packages/plugin-tailwindcss-theme":
version: 0.0.0-use.local
resolution: "@cloudbeaver/plugin-tailwindcss-theme@workspace:packages/plugin-tailwindcss-theme"
dependencies:
"@cloudbeaver/core-cli": "workspace:*"
"@cloudbeaver/core-di": "workspace:*"
"@cloudbeaver/tsconfig": "workspace:*"
"@dbeaver/cli": "workspace:*"
rimraf: "npm:^6"
tailwindcss: "npm:4.0.7"
tslib: "npm:^2"
typescript: "npm:^5"
languageName: unknown
linkType: soft
"@cloudbeaver/plugin-task-manager@workspace:*, @cloudbeaver/plugin-task-manager@workspace:packages/plugin-task-manager":
version: 0.0.0-use.local
resolution: "@cloudbeaver/plugin-task-manager@workspace:packages/plugin-task-manager"
@@ -4657,6 +4664,7 @@ __metadata:
"@cloudbeaver/core-browser": "workspace:*"
"@cloudbeaver/core-cli": "workspace:*"
"@cloudbeaver/plugin-sso": "workspace:*"
"@cloudbeaver/plugin-tailwindcss-theme": "workspace:*"
"@cloudbeaver/product-base": "workspace:*"
"@cloudbeaver/product-default-impl": "workspace:*"
"@cloudbeaver/tsconfig": "workspace:*"
@@ -6980,208 +6988,6 @@ __metadata:
languageName: node
linkType: hard
"@material/animation@npm:^4.0.0":
version: 4.0.0
resolution: "@material/animation@npm:4.0.0"
dependencies:
tslib: "npm:^1.9.3"
checksum: 10c0/793a5fffc763d17c4085ba924379553f5c9c4a1b5120437b2ebbfb86e65033db32f6d4752ce3a3de473940956db5f55afe18d5fb5b165c3b8d4d19a2c5609d9e
languageName: node
linkType: hard
"@material/base@npm:*":
version: 14.0.0
resolution: "@material/base@npm:14.0.0"
dependencies:
tslib: "npm:^2.1.0"
checksum: 10c0/4576b1d32c8c9c1e71c50b1b39f70e42ef9ca87884a9f4450a982ad272a619df4c35dde3993f1d9ca7a54219ac8eec95570a9005b40abb1ae70eaa8cf84f3dcf
languageName: node
linkType: hard
"@material/base@npm:^4.0.0":
version: 4.0.0
resolution: "@material/base@npm:4.0.0"
dependencies:
tslib: "npm:^1.9.3"
checksum: 10c0/627a311620ec4470a0d7ac9ea17233501d8241a99ef7ba101e2758f0e45faf30c36943bb137cd0612ed909d4c6fdacd87e995e20e1316fb9c846b5910e308e49
languageName: node
linkType: hard
"@material/button@npm:^4":
version: 4.0.0
resolution: "@material/button@npm:4.0.0"
dependencies:
"@material/density": "npm:^4.0.0"
"@material/elevation": "npm:^4.0.0"
"@material/feature-targeting": "npm:^4.0.0"
"@material/ripple": "npm:^4.0.0"
"@material/rtl": "npm:^4.0.0"
"@material/shape": "npm:^4.0.0"
"@material/theme": "npm:^4.0.0"
"@material/touch-target": "npm:^4.0.0"
"@material/typography": "npm:^4.0.0"
checksum: 10c0/6536b6166b33fc200e8ff5acf7045ac1b657d33247c894acb672e95e6e6abbf2b7c8e9a6e3bcd6e3b4ad3f07374da72a9c6c986c2fd8099a389b52acd2c65a7d
languageName: node
linkType: hard
"@material/checkbox@npm:^4":
version: 4.0.0
resolution: "@material/checkbox@npm:4.0.0"
dependencies:
"@material/animation": "npm:^4.0.0"
"@material/base": "npm:^4.0.0"
"@material/density": "npm:^4.0.0"
"@material/dom": "npm:^4.0.0"
"@material/feature-targeting": "npm:^4.0.0"
"@material/ripple": "npm:^4.0.0"
"@material/theme": "npm:^4.0.0"
"@material/touch-target": "npm:^4.0.0"
tslib: "npm:^1.9.3"
checksum: 10c0/8ad90d9f102a2a555b5fd24b8fb55245ca84391234e79546c6cfab136b32308148749306fdb7f1aae2c22be7632875452766aab96df00e1660faac231f695508
languageName: node
linkType: hard
"@material/density@npm:*":
version: 14.0.0
resolution: "@material/density@npm:14.0.0"
dependencies:
tslib: "npm:^2.1.0"
checksum: 10c0/d7e43fd8a007f8758404077092da783ca33118d9c782d5f2ebad214b678419a6e31133f111330031db01540e55a4f0aca2086000b8deac6b43ddacff08934107
languageName: node
linkType: hard
"@material/density@npm:^4.0.0":
version: 4.0.0
resolution: "@material/density@npm:4.0.0"
checksum: 10c0/71b8adf28167611a28c8ced4c71e311112f6b4eb32a7c21a449a8f8dc55ae9e11220aa4335f893f9ecf9d9a63fc833c52b17e3143b5506be96b38c82bac3e273
languageName: node
linkType: hard
"@material/dom@npm:^4.0.0":
version: 4.0.0
resolution: "@material/dom@npm:4.0.0"
dependencies:
tslib: "npm:^1.9.3"
checksum: 10c0/66574766fefc7f37410424333e8c88fd87e8c2fa28ade66dd02fe19d77eac9f3bf0b6d6b762d79adbea1cf4e76ed8279d040aac8003c6ce68b8c860bbc05c252
languageName: node
linkType: hard
"@material/elevation@npm:^4, @material/elevation@npm:^4.0.0":
version: 4.0.0
resolution: "@material/elevation@npm:4.0.0"
dependencies:
"@material/animation": "npm:^4.0.0"
"@material/feature-targeting": "npm:^4.0.0"
"@material/theme": "npm:^4.0.0"
checksum: 10c0/3fa4d82d67bfe84822e46fcda59fc97ad254ac361d28b63f275c6b5384f9edf214ececd8aefff2856c033b65260cd36a760cc8bf4dd1381013f5f5f6c57ceebc
languageName: node
linkType: hard
"@material/feature-targeting@npm:^4.0.0":
version: 4.0.0
resolution: "@material/feature-targeting@npm:4.0.0"
checksum: 10c0/6abf68a6de33e5e571c36dd7b61712036cd407ff9e1a16b590dd13e420228e75994f2b3c0d7ad7faedea54c11a0ffa9b0b4c00d660d007eb1f892c3415bb05b4
languageName: node
linkType: hard
"@material/layout-grid@npm:^4":
version: 4.0.0
resolution: "@material/layout-grid@npm:4.0.0"
checksum: 10c0/04780ac3689778868bc443891420d04347d7070dbebbd577892611e11826c05565db9b1bc8b4ac27d5b4a8d7cb255f9e1935697fcee79d587f341cd22f6ded94
languageName: node
linkType: hard
"@material/radio@npm:^4":
version: 4.0.0
resolution: "@material/radio@npm:4.0.0"
dependencies:
"@material/animation": "npm:^4.0.0"
"@material/base": "npm:^4.0.0"
"@material/density": "npm:^4.0.0"
"@material/dom": "npm:^4.0.0"
"@material/feature-targeting": "npm:^4.0.0"
"@material/ripple": "npm:^4.0.0"
"@material/theme": "npm:^4.0.0"
"@material/touch-target": "npm:^4.0.0"
tslib: "npm:^1.9.3"
checksum: 10c0/f1bbf104915175da13f63d2a79fc0b769219e056e9bbdf4f3493d7e78bdaf02a22b9f163b8fc165f4ee597b98efed5e67347514241c7c151896db61287f6afaa
languageName: node
linkType: hard
"@material/ripple@npm:^4, @material/ripple@npm:^4.0.0":
version: 4.0.0
resolution: "@material/ripple@npm:4.0.0"
dependencies:
"@material/animation": "npm:^4.0.0"
"@material/base": "npm:^4.0.0"
"@material/dom": "npm:^4.0.0"
"@material/feature-targeting": "npm:^4.0.0"
"@material/theme": "npm:^4.0.0"
tslib: "npm:^1.9.3"
checksum: 10c0/52e4483d2aac930d10d3ca9691f9e86eb8dd1433671e4f509a907b3df4bbebe22f46c5db111f17bf859aa14f7876afca44ee43fd7a0a370f20cb2daaa9f03c1e
languageName: node
linkType: hard
"@material/rtl@npm:^4.0.0":
version: 4.0.0
resolution: "@material/rtl@npm:4.0.0"
checksum: 10c0/2a695b5014e76b2db8b19cf3029bffec44c10cd8e1b299bcf72938faafebdcd6ea634be23548efbb060fc9cc27e0ab122e638ea827336986a8e1d32d95def760
languageName: node
linkType: hard
"@material/shape@npm:^4.0.0":
version: 4.0.0
resolution: "@material/shape@npm:4.0.0"
dependencies:
"@material/feature-targeting": "npm:^4.0.0"
checksum: 10c0/a0e04598bfb7e0d24c5b18d29abea818e27f109e30cdd384f686d034580ec1177c2988d2e3ba3a4df94ad1904d9d2b0eefe35da869804bdc1367cfa38344bcf5
languageName: node
linkType: hard
"@material/switch@npm:^4":
version: 4.0.0
resolution: "@material/switch@npm:4.0.0"
dependencies:
"@material/animation": "npm:^4.0.0"
"@material/base": "npm:^4.0.0"
"@material/dom": "npm:^4.0.0"
"@material/elevation": "npm:^4.0.0"
"@material/feature-targeting": "npm:^4.0.0"
"@material/ripple": "npm:^4.0.0"
"@material/rtl": "npm:^4.0.0"
"@material/theme": "npm:^4.0.0"
tslib: "npm:^1.9.3"
checksum: 10c0/87a189c70c11f543247a6e14e78f245db5fc397c368eefd9bc49b39146618b6613c271adaa71053f8acb9bc8e02e273743c0187b9187e54436fd0ae45770e5e9
languageName: node
linkType: hard
"@material/theme@npm:^4, @material/theme@npm:^4.0.0":
version: 4.0.0
resolution: "@material/theme@npm:4.0.0"
dependencies:
"@material/feature-targeting": "npm:^4.0.0"
checksum: 10c0/3720688b9a785e881b1769830adecc5c7a61e0210486106a951a061ed5e0b4aa6f8070552718c60e41c40000eac335f79456397532f524ec1d4c78b2b62198da
languageName: node
linkType: hard
"@material/touch-target@npm:^4.0.0":
version: 4.0.0
resolution: "@material/touch-target@npm:4.0.0"
dependencies:
"@material/feature-targeting": "npm:^4.0.0"
checksum: 10c0/fd22140923cac852b27dbc44885f7119269eefa1da4426a62571b3a841da6bf7c671decb0a909839d512ab540439241e8efb69adcfc1b8c31b1d65c155083056
languageName: node
linkType: hard
"@material/typography@npm:^4, @material/typography@npm:^4.0.0":
version: 4.0.0
resolution: "@material/typography@npm:4.0.0"
dependencies:
"@material/feature-targeting": "npm:^4.0.0"
checksum: 10c0/071cbdffd8109aa3def679636d119200b61416040ddff6e1df368f789416cb9dbcad32e868f2723871627133fc6eaab973e59e915f298e63d7a3bc8422b0ff06
languageName: node
linkType: hard
"@mdx-js/mdx@npm:^3.1.0":
version: 3.1.1
resolution: "@mdx-js/mdx@npm:3.1.1"
@@ -18838,7 +18644,7 @@ __metadata:
languageName: node
linkType: hard
"tslib@npm:^1.10.0, tslib@npm:^1.9.3":
"tslib@npm:^1.10.0":
version: 1.14.1
resolution: "tslib@npm:1.14.1"
checksum: 10c0/69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2