diff --git a/.gitignore b/.gitignore index 59c717a451..216ba60082 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ yarn-debug.log* yarn-error.log* css +!__mocks__/css tsconfig.tsbuildinfo packages/*/package-lock.json diff --git a/__mocks__/css/mock-theme-dark-components.js b/__mocks__/css/mock-theme-dark-components.js new file mode 100644 index 0000000000..c5560b1294 --- /dev/null +++ b/__mocks__/css/mock-theme-dark-components.js @@ -0,0 +1 @@ +module.exports = 'mock-theme-dark-components'; diff --git a/__mocks__/css/mock-theme-dark-palette.js b/__mocks__/css/mock-theme-dark-palette.js new file mode 100644 index 0000000000..21854c8c09 --- /dev/null +++ b/__mocks__/css/mock-theme-dark-palette.js @@ -0,0 +1 @@ +module.exports = 'mock-theme-dark-palette'; diff --git a/__mocks__/css/mock-theme-dark-semantic-editor.js b/__mocks__/css/mock-theme-dark-semantic-editor.js new file mode 100644 index 0000000000..48ec449051 --- /dev/null +++ b/__mocks__/css/mock-theme-dark-semantic-editor.js @@ -0,0 +1 @@ +module.exports = 'mock-theme-dark-semantic-editor'; diff --git a/__mocks__/css/mock-theme-dark-semantic-grid.js b/__mocks__/css/mock-theme-dark-semantic-grid.js new file mode 100644 index 0000000000..a0cf67fa6d --- /dev/null +++ b/__mocks__/css/mock-theme-dark-semantic-grid.js @@ -0,0 +1 @@ +module.exports = 'mock-theme-dark-semantic-grid'; diff --git a/__mocks__/css/mock-theme-dark-semantic.js b/__mocks__/css/mock-theme-dark-semantic.js new file mode 100644 index 0000000000..1d252429d9 --- /dev/null +++ b/__mocks__/css/mock-theme-dark-semantic.js @@ -0,0 +1 @@ +module.exports = 'mock-theme-dark-semantic'; diff --git a/__mocks__/css/mock-theme-light-palette.js b/__mocks__/css/mock-theme-light-palette.js new file mode 100644 index 0000000000..e664d94101 --- /dev/null +++ b/__mocks__/css/mock-theme-light-palette.js @@ -0,0 +1 @@ +module.exports = 'mock-theme-light-palette'; diff --git a/__mocks__/css/mock-theme-spectrum-alias.module.js b/__mocks__/css/mock-theme-spectrum-alias.module.js new file mode 100644 index 0000000000..e1b3cb449c --- /dev/null +++ b/__mocks__/css/mock-theme-spectrum-alias.module.js @@ -0,0 +1,3 @@ +module.exports = { + 'dh-spectrum-alias': 'mock-dh-spectrum-alias', +}; diff --git a/__mocks__/css/mock-theme-spectrum-overrides.module.js b/__mocks__/css/mock-theme-spectrum-overrides.module.js new file mode 100644 index 0000000000..4788e1aad0 --- /dev/null +++ b/__mocks__/css/mock-theme-spectrum-overrides.module.js @@ -0,0 +1,3 @@ +module.exports = { + 'dh-spectrum-overrides': 'mock-dh-spectrum-overrides', +}; diff --git a/__mocks__/css/mock-theme-spectrum-palette.module.js b/__mocks__/css/mock-theme-spectrum-palette.module.js new file mode 100644 index 0000000000..0ad7ec6ec2 --- /dev/null +++ b/__mocks__/css/mock-theme-spectrum-palette.module.js @@ -0,0 +1,3 @@ +module.exports = { + 'dh-spectrum-palette': 'mock-dh-spectrum-palette', +}; diff --git a/__mocks__/spectrumThemeDarkMock.js b/__mocks__/spectrumThemeDarkMock.js deleted file mode 100644 index ae129ec995..0000000000 --- a/__mocks__/spectrumThemeDarkMock.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - 'dh-spectrum-theme--dark': 'mock.dark', -}; diff --git a/__mocks__/spectrumThemeLightMock.js b/__mocks__/spectrumThemeLightMock.js deleted file mode 100644 index 30b205f5a3..0000000000 --- a/__mocks__/spectrumThemeLightMock.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - 'dh-spectrum-theme--light': 'mock.light', -}; diff --git a/jest.config.base.cjs b/jest.config.base.cjs index 373bf89b78..05be728cb4 100644 --- a/jest.config.base.cjs +++ b/jest.config.base.cjs @@ -9,9 +9,9 @@ module.exports = { 'node_modules/(?!(monaco-editor|d3-interpolate|d3-color)/)', ], moduleNameMapper: { - 'SpectrumTheme([^.]+)\\.module\\.scss$': path.join( + 'theme-([^/]+?)\\.css(\\?inline)?$': path.join( __dirname, - './__mocks__/spectrumTheme$1Mock.js' + './__mocks__/css/mock-theme-$1.js' ), '\\.(css|less|scss|sass)$': 'identity-obj-proxy', '\\.(css|less|scss|sass)\\?inline$': path.join( diff --git a/package-lock.json b/package-lock.json index fac28af5cd..8770635b06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,7 +59,7 @@ "@deephaven/tsconfig": "file:../tsconfig", "@deephaven/utils": "file:../utils", "@fortawesome/fontawesome-common-types": "^6.1.1", - "@playwright/test": "^1.37.1", + "@playwright/test": "1.37.1", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.1", diff --git a/package.json b/package.json index edf80f7449..859019a992 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "@deephaven/tsconfig": "file:../tsconfig", "@deephaven/utils": "file:../utils", "@fortawesome/fontawesome-common-types": "^6.1.1", - "@playwright/test": "^1.37.1", + "@playwright/test": "1.37.1", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.1", diff --git a/packages/app-utils/src/components/AppBootstrap.test.tsx b/packages/app-utils/src/components/AppBootstrap.test.tsx index 84a474a42d..dc838d24b7 100644 --- a/packages/app-utils/src/components/AppBootstrap.test.tsx +++ b/packages/app-utils/src/components/AppBootstrap.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { AUTH_HANDLER_TYPE_ANONYMOUS } from '@deephaven/auth-plugins'; import { ApiContext } from '@deephaven/jsapi-bootstrap'; import { BROADCAST_LOGIN_MESSAGE } from '@deephaven/jsapi-utils'; @@ -10,6 +10,18 @@ import type { import { TestUtils } from '@deephaven/utils'; import { act, render, screen } from '@testing-library/react'; import AppBootstrap from './AppBootstrap'; +import { PluginsContext } from './PluginsBootstrap'; +import { PluginModuleMap } from '../plugins'; + +const { asMock } = TestUtils; + +jest.mock('react', () => { + const actual = jest.requireActual('react'); + return { + ...actual, + useContext: jest.fn(actual.useContext), + }; +}); const API_URL = 'http://mockserver.net:8111'; const PLUGINS_URL = 'http://mockserver.net:8111/plugins'; @@ -33,6 +45,7 @@ jest.mock('@deephaven/jsapi-components', () => ({ const mockChildText = 'Mock Child'; const mockChild =
{mockChildText}
; +const mockPluginModuleMapEmpty: PluginModuleMap = new Map(); function expectMockChild() { return expect(screen.queryByText(mockChildText)); @@ -60,6 +73,17 @@ beforeEach(() => { it('should throw if api has not been bootstrapped', () => { TestUtils.disableConsoleOutput(); + asMock(useContext).mockImplementation(context => { + // ThemeBootstrap doesn't render children until plugins are loaded. We need + // a non-null PluginsContext value to render the children and get the expected + // missing api error. + if (context === PluginsContext) { + return mockPluginModuleMapEmpty; + } + + return jest.requireActual('react').useContext(context); + }); + expect(() => render( diff --git a/packages/code-studio/src/styleguide/GotoTopButton.css b/packages/code-studio/src/styleguide/GotoTopButton.css new file mode 100644 index 0000000000..681a8f8871 --- /dev/null +++ b/packages/code-studio/src/styleguide/GotoTopButton.css @@ -0,0 +1,19 @@ +/* + * GotoTopButton is only visible if user has scrolled down. Visibility attribute + * can't really make use of CSS transitions, so we use opacity instead. Including + * visibility for accessibility reasons. + */ +.goto-top-button { + visibility: visible; + opacity: 1; + transition: + opacity 300ms, + visibility 0s linear 0s; +} +html:not([data-scroll='true']) .goto-top-button { + visibility: hidden; + opacity: 0; + transition: + opacity 300ms, + visibility 0s linear 300ms; +} diff --git a/packages/code-studio/src/styleguide/GotoTopButton.tsx b/packages/code-studio/src/styleguide/GotoTopButton.tsx new file mode 100644 index 0000000000..f51039c4f7 --- /dev/null +++ b/packages/code-studio/src/styleguide/GotoTopButton.tsx @@ -0,0 +1,48 @@ +import React, { useCallback, useEffect } from 'react'; +import { Button, Icon } from '@adobe/react-spectrum'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { vsChevronUp } from '@deephaven/icons'; +import './GotoTopButton.css'; + +/** + * Button that scrolls to top of styleguide and clears location hash. + */ +export function GotoTopButton(): JSX.Element { + const gotoTop = useCallback(() => { + window.scrollTo({ + top: 0, + behavior: 'smooth', + }); + + // Small delay to give scrolling a chance to move smoothly to top + setTimeout(() => { + window.location.hash = ''; + }, 500); + }, []); + + // Set data-scroll="true" on the html element when the user scrolls down below + // 120px. CSS uses this to only show the button when the user has scrolled. + useEffect(() => { + function onScroll() { + document.documentElement.dataset.scroll = String(window.scrollY > 120); + } + document.addEventListener('scroll', onScroll, { passive: true }); + return () => { + document.removeEventListener('scroll', onScroll); + }; + }, []); + + return ( + + ); +} + +export default GotoTopButton; diff --git a/packages/code-studio/src/styleguide/Icons.tsx b/packages/code-studio/src/styleguide/Icons.tsx index efd25ac9cf..ce2e3f0b32 100644 --- a/packages/code-studio/src/styleguide/Icons.tsx +++ b/packages/code-studio/src/styleguide/Icons.tsx @@ -6,6 +6,7 @@ import { dhSquareFilled, dhAddSmall, } from '@deephaven/icons'; +import { Icon } from '@adobe/react-spectrum'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button } from '@deephaven/components'; import PropTypes from 'prop-types'; @@ -106,7 +107,9 @@ function Icons(): React.ReactElement { }); }} > - + + + diff --git a/packages/code-studio/src/styleguide/SamplesMenu.tsx b/packages/code-studio/src/styleguide/SamplesMenu.tsx new file mode 100644 index 0000000000..81e7a935ca --- /dev/null +++ b/packages/code-studio/src/styleguide/SamplesMenu.tsx @@ -0,0 +1,125 @@ +import React, { Key, useCallback, useEffect, useState } from 'react'; +import { + ActionButton, + Icon, + Item, + Menu, + MenuTrigger, + Section, +} from '@adobe/react-spectrum'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { vsMenu } from '@deephaven/icons'; +import { + MENU_CATEGORY_DATA_ATTRIBUTE, + NO_MENU_DATA_ATTRIBUTE, + SPECTRUM_COMPONENT_SAMPLES_ID, +} from './constants'; + +interface Link { + id: string; + label: string; +} +type LinkCategory = { category: string; items: Link[] }; + +/** + * Metadata only div that provides a MENU_CATEGORY_DATA_ATTRIBUTE defining a + * menu category. These will be queried by the SamplesMenu component to build + * up the menu sections. + */ +export function SampleMenuCategory({ + 'data-menu-category': dataMenuCategory, +}: Record): JSX.Element { + return
; +} + +/** + * Creates a menu from h2, h3 elements on the page and assigns them each an id + * for hash navigation purposes. If the current hash matches one of the ids, it + * will scroll to that element. This handles the initial page load scenario. + * Menu sections are identified by divs with MENU_CATEGORY_DATA_ATTRIBUTE + * attributes. + */ +export function SamplesMenu(): JSX.Element { + const [links, setLinks] = useState([]); + + useEffect(() => { + let currentCategory: LinkCategory = { + category: '', + items: [], + }; + const categories: LinkCategory[] = [currentCategory]; + + const spectrumComponentsSamples = document.querySelector( + `#${SPECTRUM_COMPONENT_SAMPLES_ID}` + ); + + document + .querySelectorAll(`h2,h3,[${MENU_CATEGORY_DATA_ATTRIBUTE}]`) + .forEach(el => { + if (el.textContent == null || el.hasAttribute(NO_MENU_DATA_ATTRIBUTE)) { + return; + } + + // Create a new category section + if (el.hasAttribute(MENU_CATEGORY_DATA_ATTRIBUTE)) { + currentCategory = { + category: el.getAttribute(MENU_CATEGORY_DATA_ATTRIBUTE) ?? '', + items: [], + }; + categories.push(currentCategory); + + return; + } + + const id = `${ + spectrumComponentsSamples?.contains(el) === true ? 'spectrum-' : '' + }${el.textContent}` + .toLowerCase() + .replace(/\s/g, '-'); + + // eslint-disable-next-line no-param-reassign + el.id = id; + + currentCategory.items.push({ id, label: el.textContent }); + + if (`#${id}` === window.location.hash) { + el.scrollIntoView(); + } + }); + + setLinks(categories); + }, []); + + const onAction = useCallback((key: Key) => { + const id = String(key); + const el = document.getElementById(id); + el?.scrollIntoView({ + behavior: 'smooth', + }); + + // Keep hash in sync for page reloads, but give some delay to allow smooth + // scrolling above + setTimeout(() => { + window.location.hash = id; + }, 500); + }, []); + + return ( + + + + + + + + {({ category, items }) => ( +
+ {({ id, label }) => {label}} +
+ )} +
+
+ ); +} + +export default SamplesMenu; diff --git a/packages/code-studio/src/styleguide/SpectrumComponents.tsx b/packages/code-studio/src/styleguide/SpectrumComponents.tsx new file mode 100644 index 0000000000..697fb87f9c --- /dev/null +++ b/packages/code-studio/src/styleguide/SpectrumComponents.tsx @@ -0,0 +1,235 @@ +/* eslint-disable react/style-prop-object */ +import React from 'react'; +import { + ActionButton, + Button, + Cell, + Checkbox, + Content, + ContextualHelp, + Column, + ComboBox, + Form, + Heading, + Grid, + Icon, + IllustratedMessage, + Item, + minmax, + repeat, + Row, + Slider, + Switch, + TableBody, + TableHeader, + TableView, + Text, + TextField, + ToggleButton, + View, + Well, +} from '@adobe/react-spectrum'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { dh } from '@deephaven/icons'; +import { SPECTRUM_COMPONENT_SAMPLES_ID } from './constants'; + +export function SpectrumComponents(): JSX.Element { + return ( +
+

+ Spectrum Components +

+ + +

Buttons

+ +
+ +

Collections

+ +
+ +

Content

+ +
+ +

Forms

+ +
+ +

Overlays

+ +
+ +

Wells

+ This is a well. +
+
+
+ ); +} + +export default SpectrumComponents; + +function ButtonsSample(): JSX.Element { + return ( + + + + + + + + + + + + + + + + + + + + + Normal + + Quiet + + Static Black + Static White + Disabled + + + Normal + Quiet + + Emphasized + + Static Black + Static White + Disabled + + ); +} + +function ContextualHelpSample(): JSX.Element { + return ( + <> + Contextual Help + + Need help? + + + This is a helpful description of the thing you need help with. + + + + + ); +} + +function FormsSample(): JSX.Element { + return ( +
+ + + + One + Two + Three + + Checkbox + + Switch + +
+ ); +} + +function IllustratedMessageSample(): JSX.Element { + return ( + + + + + Illustrated Message + This is the content of the message. + + ); +} + +function TableViewSample(): JSX.Element { + return ( + <> + + + + + Name + Age + + + City + State + + + + + John + 42 + San Francisco + CA + + + Jane + 38 + San Francisco + CA + + + Becky + 12 + San Francisco + CA + + + + + ); +} diff --git a/packages/code-studio/src/styleguide/StyleGuide.scss b/packages/code-studio/src/styleguide/StyleGuide.scss index 58d270d8e2..3f77914e82 100644 --- a/packages/code-studio/src/styleguide/StyleGuide.scss +++ b/packages/code-studio/src/styleguide/StyleGuide.scss @@ -125,11 +125,6 @@ h5.sub-title { } } - .icon, - .icon .svg-inline--fa { - font-size: 36px; - } - .card label { max-width: 100%; font-size: 0.8rem; diff --git a/packages/code-studio/src/styleguide/StyleGuide.test.tsx b/packages/code-studio/src/styleguide/StyleGuide.test.tsx index 69e84a2bd2..d6d2d324d4 100644 --- a/packages/code-studio/src/styleguide/StyleGuide.test.tsx +++ b/packages/code-studio/src/styleguide/StyleGuide.test.tsx @@ -1,15 +1,21 @@ import React from 'react'; import { render } from '@testing-library/react'; +import { ThemeData, ThemeProvider } from '@deephaven/components'; import { dh } from '@deephaven/jsapi-shim'; import { ApiContext } from '@deephaven/jsapi-bootstrap'; import StyleGuide from './StyleGuide'; describe(' mounts', () => { test('h1 text of StyleGuide renders', () => { + // Provide a non-null array to ThemeProvider to tell it to initialize + const customThemes: ThemeData[] = []; + expect(() => render( - + + + ) ).not.toThrow(); diff --git a/packages/code-studio/src/styleguide/StyleGuide.tsx b/packages/code-studio/src/styleguide/StyleGuide.tsx index a71843a61c..6bc7911999 100644 --- a/packages/code-studio/src/styleguide/StyleGuide.tsx +++ b/packages/code-studio/src/styleguide/StyleGuide.tsx @@ -1,4 +1,6 @@ +/* eslint-disable react/jsx-props-no-spreading */ import React from 'react'; +import { Flex } from '@adobe/react-spectrum'; import { ContextMenuRoot } from '@deephaven/components'; import Alerts from './Alerts'; @@ -22,55 +24,63 @@ import './StyleGuide.scss'; import DraggableLists from './DraggableLists'; import Navigations from './Navigations'; import ThemeColors from './ThemeColors'; +import SpectrumComponents from './SpectrumComponents'; +import SamplesMenu, { SampleMenuCategory } from './SamplesMenu'; +import GotoTopButton from './GotoTopButton'; + +const stickyProps = { + position: 'sticky', + justifyContent: 'end', + zIndex: 1, +} as const; function StyleGuide(): React.ReactElement { return (
-
+

Deephaven UI Components

-
+ + + + + + + + + - + - - - - - - - - - - - - - - - - - + + +
); } diff --git a/packages/code-studio/src/styleguide/ThemeColors.tsx b/packages/code-studio/src/styleguide/ThemeColors.tsx index 07e2ca95ad..dc7ba764cf 100644 --- a/packages/code-studio/src/styleguide/ThemeColors.tsx +++ b/packages/code-studio/src/styleguide/ThemeColors.tsx @@ -5,6 +5,7 @@ import palette from '@deephaven/components/src/theme/theme-dark/theme-dark-palet import semantic from '@deephaven/components/src/theme/theme-dark/theme-dark-semantic.css?inline'; import semanticEditor from '@deephaven/components/src/theme/theme-dark/theme-dark-semantic-editor.css?inline'; import semanticGrid from '@deephaven/components/src/theme/theme-dark/theme-dark-semantic-grid.css?inline'; +import components from '@deephaven/components/src/theme/theme-dark/theme-dark-components.css?inline'; import styles from './ThemeColors.module.scss'; // Group names are extracted from var names via a regex capture group. Most of @@ -45,15 +46,23 @@ const renameGroups = { focus: 'state', }, grid: { data: 'Data Bars', context: 'Context Menu' }, + semantic: { + positive: 'status', + negative: 'status', + notice: 'status', + info: 'status', + well: 'wells', + }, }; export function ThemeColors(): JSX.Element { const swatchDataGroups = useMemo( () => ({ 'Theme Color Palette': buildColorGroups(palette, 1), - 'Semantic Colors': buildColorGroups(semantic, 1), + 'Semantic Colors': buildColorGroups(semantic, 1, renameGroups.semantic), 'Editor Colors': buildColorGroups(semanticEditor, 2, renameGroups.editor), 'Grid Colors': buildColorGroups(semanticGrid, 2, renameGroups.grid), + 'Component Colors': buildColorGroups(components, 1), }), [] ); diff --git a/packages/code-studio/src/styleguide/Typography.tsx b/packages/code-studio/src/styleguide/Typography.tsx index 747e2ec79e..a9255d2f55 100644 --- a/packages/code-studio/src/styleguide/Typography.tsx +++ b/packages/code-studio/src/styleguide/Typography.tsx @@ -3,15 +3,23 @@ import React from 'react'; function Typography(): React.ReactElement { return (
-

Typograpy

+

Typography

-

h1. Unused

-

h2. Unused

-

h3. Unused

-

h4. Standard Heading

-
h5. Small Heading
-
h6. Unused
+

+ h1. Unused +

+

+ h2. Unused +

+

+ h3. Unused +

+

h4. Standard Heading

+
h5. Small Heading
+
+ h6. Unused +
diff --git a/packages/code-studio/src/styleguide/constants.ts b/packages/code-studio/src/styleguide/constants.ts new file mode 100644 index 0000000000..af5b342f11 --- /dev/null +++ b/packages/code-studio/src/styleguide/constants.ts @@ -0,0 +1,3 @@ +export const MENU_CATEGORY_DATA_ATTRIBUTE = 'data-menu-category'; +export const NO_MENU_DATA_ATTRIBUTE = 'data-no-menu'; +export const SPECTRUM_COMPONENT_SAMPLES_ID = 'spectrum-component-samples'; diff --git a/packages/components/src/SpectrumThemeDark.module.scss b/packages/components/src/SpectrumThemeDark.module.scss deleted file mode 100644 index 2def9236d9..0000000000 --- a/packages/components/src/SpectrumThemeDark.module.scss +++ /dev/null @@ -1,12 +0,0 @@ -/** - This module contains overrides of React Spectrum css variables for the default - `dark` Deephaven theme. -*/ -@use '../scss/bootstrap_overrides' as bootstrap; -@use '../scss/util' as *; - -// Doubling specificity to ensure this takes precedence over default Spectrum -// styles. -#{multiply-specificity-n('.dh-spectrum-theme--dark', 2)} { - --spectrum-alias-background-color-default: #{bootstrap.$interfaceblack}; -} diff --git a/packages/components/src/SpectrumThemeLight.module.scss b/packages/components/src/SpectrumThemeLight.module.scss deleted file mode 100644 index 037ec68732..0000000000 --- a/packages/components/src/SpectrumThemeLight.module.scss +++ /dev/null @@ -1,12 +0,0 @@ -/** - This module contains overrides of React Spectrum css variables for the default - `light` Deephaven theme. -*/ -@use '../scss/bootstrap_overrides' as bootstrap; -@use '../scss/util' as *; - -// Doubling specificity to ensure this takes precedence over default Spectrum -// styles. -#{multiply-specificity-n('.dh-spectrum-theme--light', 2)} { - --spectrum-alias-background-color-default: #{bootstrap.$interfacewhite}; -} diff --git a/packages/components/src/SpectrumUtils.test.ts b/packages/components/src/SpectrumUtils.test.ts index c1e40405db..7f5ce71337 100644 --- a/packages/components/src/SpectrumUtils.test.ts +++ b/packages/components/src/SpectrumUtils.test.ts @@ -1,22 +1,7 @@ -import { theme } from '@react-spectrum/theme-default'; import { themeDHDefault } from './SpectrumUtils'; describe('themeDHDefault', () => { it('should merge Spectrum default with DH custom styles', () => { - const { global, light, dark, medium, large } = theme; - - expect(themeDHDefault).toEqual({ - global, - light: { - ...light, - 'dh-spectrum-theme--light': 'mock.light', - }, - dark: { - ...dark, - 'dh-spectrum-theme--dark': 'mock.dark', - }, - medium, - large, - }); + expect(themeDHDefault).toMatchSnapshot(); }); }); diff --git a/packages/components/src/SpectrumUtils.ts b/packages/components/src/SpectrumUtils.ts index 70f676a363..95e6f7e995 100644 --- a/packages/components/src/SpectrumUtils.ts +++ b/packages/components/src/SpectrumUtils.ts @@ -1,6 +1,5 @@ import { theme } from '@react-spectrum/theme-default'; -import darkDH from './SpectrumThemeDark.module.scss'; -import lightDH from './SpectrumThemeLight.module.scss'; +import { themeSpectrumClassesCommon } from './theme/theme-spectrum'; const { global, light, dark, medium, large } = theme; @@ -42,11 +41,11 @@ export const themeDHDefault = { global, light: { ...light, - ...lightDH, + ...themeSpectrumClassesCommon, }, dark: { ...dark, - ...darkDH, + ...themeSpectrumClassesCommon, }, // scales medium, diff --git a/packages/components/src/__snapshots__/SpectrumUtils.test.ts.snap b/packages/components/src/__snapshots__/SpectrumUtils.test.ts.snap new file mode 100644 index 0000000000..f5973cdacc --- /dev/null +++ b/packages/components/src/__snapshots__/SpectrumUtils.test.ts.snap @@ -0,0 +1,33 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`themeDHDefault should merge Spectrum default with DH custom styles 1`] = ` +{ + "dark": { + "dh-spectrum-alias": "mock-dh-spectrum-alias", + "dh-spectrum-overrides": "mock-dh-spectrum-overrides", + "dh-spectrum-palette": "mock-dh-spectrum-palette", + "spectrum--darkest": "spectrum--darkest_256eeb", + }, + "global": { + "spectrum": "spectrum_9e130c", + "spectrum--dark": "spectrum--dark_9e130c", + "spectrum--darkest": "spectrum--darkest_9e130c", + "spectrum--large": "spectrum--large_9e130c", + "spectrum--light": "spectrum--light_9e130c", + "spectrum--lightest": "spectrum--lightest_9e130c", + "spectrum--medium": "spectrum--medium_9e130c", + }, + "large": { + "spectrum--large": "spectrum--large_c40598", + }, + "light": { + "dh-spectrum-alias": "mock-dh-spectrum-alias", + "dh-spectrum-overrides": "mock-dh-spectrum-overrides", + "dh-spectrum-palette": "mock-dh-spectrum-palette", + "spectrum--light": "spectrum--light_a40724", + }, + "medium": { + "spectrum--medium": "spectrum--medium_4b172c", + }, +} +`; diff --git a/packages/components/src/declaration.d.ts b/packages/components/src/declaration.d.ts index fde32658a1..f1577432ee 100644 --- a/packages/components/src/declaration.d.ts +++ b/packages/components/src/declaration.d.ts @@ -1,3 +1,7 @@ +declare module '*.module.css' { + const content: Record; + export default content; +} declare module '*.module.scss' { const content: Record; export default content; diff --git a/packages/components/src/theme/SpectrumThemeProvider.tsx b/packages/components/src/theme/SpectrumThemeProvider.tsx new file mode 100644 index 0000000000..6b190e1c32 --- /dev/null +++ b/packages/components/src/theme/SpectrumThemeProvider.tsx @@ -0,0 +1,37 @@ +import { ReactNode, useState } from 'react'; +import { Provider } from '@adobe/react-spectrum'; +import type { Theme } from '@react-types/provider'; +import shortid from 'shortid'; +import { themeDHDefault } from '../SpectrumUtils'; + +export interface SpectrumThemeProviderProps { + children: ReactNode; + isPortal?: boolean; + theme?: Theme; + colorScheme?: 'light' | 'dark'; +} + +/** + * Wrapper around React Spectrum's theme Provider that provides DH mappings of + * Spectrum's theme variables to DH's theme variables. Also exposes an optional + * `isPortal` prop that if provided, adds a unique `data-unique-id` attribute to + * the Provider. This is needed to force the Provider to render the theme wrapper + * inside of portals. + */ +export function SpectrumThemeProvider({ + children, + isPortal = false, + theme = themeDHDefault, + colorScheme, +}: SpectrumThemeProviderProps): JSX.Element { + // a unique ID is used per provider to force it to render the theme wrapper element inside portals + // based on https://github.com/adobe/react-spectrum/issues/1697#issuecomment-999827266 + // won't be needed if https://github.com/adobe/react-spectrum/pull/2669 is merged + const [id] = useState(isPortal ? shortid() : null); + + return ( + + {children} + + ); +} diff --git a/packages/components/src/theme/ThemeProvider.test.tsx b/packages/components/src/theme/ThemeProvider.test.tsx index 11856899fe..8fb489461a 100644 --- a/packages/components/src/theme/ThemeProvider.test.tsx +++ b/packages/components/src/theme/ThemeProvider.test.tsx @@ -75,18 +75,20 @@ describe('ThemeProvider', () => { assertNotNull(themeContextValueRef.current); - expect(themeContextValueRef.current.activeThemes).toEqual( - themes == null - ? null - : getActiveThemes(preloadData?.themeKey ?? DEFAULT_DARK_THEME_KEY, { - base: getDefaultBaseThemes(), - custom: themes, - }) - ); + if (themes == null) { + expect(themeContextValueRef.current.activeThemes).toBeNull(); + } else { + expect(themeContextValueRef.current.activeThemes).toEqual( + getActiveThemes(preloadData?.themeKey ?? DEFAULT_DARK_THEME_KEY, { + base: getDefaultBaseThemes(), + custom: themes, + }) + ); - expect(themeContextValueRef.current.selectedThemeKey).toEqual( - preloadData?.themeKey ?? DEFAULT_DARK_THEME_KEY - ); + expect(themeContextValueRef.current.selectedThemeKey).toEqual( + preloadData?.themeKey ?? DEFAULT_DARK_THEME_KEY + ); + } expect(component.baseElement).toMatchSnapshot(); } @@ -108,10 +110,14 @@ describe('ThemeProvider', () => { ); - expect(setThemePreloadData).toHaveBeenCalledWith({ - themeKey: preloadData?.themeKey ?? DEFAULT_DARK_THEME_KEY, - preloadStyleContent: calculatePreloadStyleContent(), - }); + if (themes == null) { + expect(setThemePreloadData).not.toHaveBeenCalled(); + } else { + expect(setThemePreloadData).toHaveBeenCalledWith({ + themeKey: preloadData?.themeKey ?? DEFAULT_DARK_THEME_KEY, + preloadStyleContent: calculatePreloadStyleContent(), + }); + } } ); @@ -127,20 +133,24 @@ describe('ThemeProvider', () => { assertNotNull(themeContextValueRef.current); - act(() => { - themeContextValueRef.current!.setSelectedThemeKey(themeKey); - }); + if (themes == null) { + expect(themeContextValueRef.current.activeThemes).toBeNull(); + } else { + act(() => { + themeContextValueRef.current!.setSelectedThemeKey(themeKey); + }); - expect(themeContextValueRef.current.activeThemes).toEqual( - themes == null - ? null - : getActiveThemes(themeKey, { - base: getDefaultBaseThemes(), - custom: themes, - }) - ); + expect(themeContextValueRef.current.activeThemes).toEqual( + getActiveThemes(themeKey, { + base: getDefaultBaseThemes(), + custom: themes, + }) + ); - expect(themeContextValueRef.current.selectedThemeKey).toEqual(themeKey); + expect(themeContextValueRef.current.selectedThemeKey).toEqual( + themeKey + ); + } expect(component.baseElement).toMatchSnapshot(); } diff --git a/packages/components/src/theme/ThemeProvider.tsx b/packages/components/src/theme/ThemeProvider.tsx index d3ff14d0ec..abf61a9800 100644 --- a/packages/components/src/theme/ThemeProvider.tsx +++ b/packages/components/src/theme/ThemeProvider.tsx @@ -8,6 +8,7 @@ import { getThemePreloadData, setThemePreloadData, } from './ThemeUtils'; +import { SpectrumThemeProvider } from './SpectrumThemeProvider'; export interface ThemeContextValue { activeThemes: ThemeData[] | null; @@ -20,6 +21,11 @@ const log = Log.module('ThemeProvider'); export const ThemeContext = createContext(null); export interface ThemeProviderProps { + /* + * Additional themes to load in addition to the base themes. If no additional + * themes are to be loaded, this must be set to an empty array in order to + * tell the provider to activate the base themes. + */ themes: ThemeData[] | null; children: ReactNode; } @@ -34,11 +40,9 @@ export function ThemeProvider({ () => getThemePreloadData()?.themeKey ?? DEFAULT_DARK_THEME_KEY ); + // Calculate active themes once a non-null themes array is provided. const activeThemes = useMemo( () => - // Themes remain inactive until a non-null themes array is provided. This - // avoids the default base theme overriding the preload if we are waiting - // on additional themes to be available. themes == null ? null : getActiveThemes(selectedThemeKey, { @@ -50,14 +54,26 @@ export function ThemeProvider({ useEffect( function updateThemePreloadData() { - log.debug('Active themes:', activeThemes?.map(theme => theme.themeKey)); + // Don't update preload data until themes have been loaded and activated + if (activeThemes == null || themes == null) { + return; + } + + const preloadStyleContent = calculatePreloadStyleContent(); + + log.debug2('updateThemePreloadData:', { + active: activeThemes.map(theme => theme.themeKey), + all: themes.map(theme => theme.themeKey), + preloadStyleContent, + selectedThemeKey, + }); setThemePreloadData({ themeKey: selectedThemeKey, - preloadStyleContent: calculatePreloadStyleContent(), + preloadStyleContent, }); }, - [activeThemes, selectedThemeKey] + [activeThemes, selectedThemeKey, themes] ); const value = useMemo( @@ -71,12 +87,16 @@ export function ThemeProvider({ return ( - {activeThemes?.map(theme => ( - - ))} - {children} + {activeThemes == null ? null : ( + <> + {activeThemes.map(theme => ( + + ))} + + )} + {children} ); } diff --git a/packages/components/src/theme/ThemeUtils.test.ts b/packages/components/src/theme/ThemeUtils.test.ts index ba34a9b329..bf53d632d8 100644 --- a/packages/components/src/theme/ThemeUtils.test.ts +++ b/packages/components/src/theme/ThemeUtils.test.ts @@ -191,13 +191,18 @@ describe('getDefaultBaseThemes', () => { { name: 'Default Dark', themeKey: 'default-dark', - styleContent: - 'test-file-stub\ntest-file-stub\ntest-file-stub\ntest-file-stub', + styleContent: [ + 'mock-theme-dark-palette', + 'mock-theme-dark-semantic', + 'mock-theme-dark-semantic-editor', + 'mock-theme-dark-semantic-grid', + 'mock-theme-dark-components', + ].join('\n'), }, { name: 'Default Light', themeKey: 'default-light', - styleContent: 'test-file-stub', + styleContent: 'mock-theme-light-palette', }, ]); }); diff --git a/packages/components/src/theme/__snapshots__/ThemeProvider.test.tsx.snap b/packages/components/src/theme/__snapshots__/ThemeProvider.test.tsx.snap index 33d1ae08e2..30808714c6 100644 --- a/packages/components/src/theme/__snapshots__/ThemeProvider.test.tsx.snap +++ b/packages/components/src/theme/__snapshots__/ThemeProvider.test.tsx.snap @@ -6,10 +6,17 @@ exports[`ThemeProvider setSelectedThemeKey: [ [Object] ] should change selected -
- Child +
+
+ Child +
@@ -21,16 +28,24 @@ exports[`ThemeProvider setSelectedThemeKey: [ [Object] ] should change selected -
- Child +
+
+ Child +
@@ -98,8 +143,15 @@ test-file-stub exports[`ThemeProvider should load themes based on preload data or default: null, { themeKey: 'themeA' } 1`] = `
-
- Child +
+
+ Child +
@@ -108,8 +160,15 @@ exports[`ThemeProvider should load themes based on preload data or default: null exports[`ThemeProvider should load themes based on preload data or default: null, null 1`] = `
-
- Child +
+
+ Child +
diff --git a/packages/components/src/theme/theme-dark/index.ts b/packages/components/src/theme/theme-dark/index.ts index 04f5f09c2b..e5f40db52a 100644 --- a/packages/components/src/theme/theme-dark/index.ts +++ b/packages/components/src/theme/theme-dark/index.ts @@ -2,12 +2,38 @@ import themeDarkPalette from './theme-dark-palette.css?inline'; import themeDarkSemantic from './theme-dark-semantic.css?inline'; import themeDarkSemanticEditor from './theme-dark-semantic-editor.css?inline'; import themeDarkSemanticGrid from './theme-dark-semantic-grid.css?inline'; +import themeDarkComponents from './theme-dark-components.css?inline'; +/** + * DH theme variables are imported via Vite `?inline` query which provides the + * text content of the variable files as a string. The exported theme is just a + * concatenation of the contents of all of these imports. + * + * e.g. + * + * :root { + * --dh-color-from-dark-palette: #fff; + * --dh-color-from-dark-palette2: #ccc; + * } + * :root { + * --dh-color-from-dark-semantic: #000; + * } + * :root { + * --dh-color-from-dark-semantic-editor: #000; + * } + * :root { + * --dh-color-from-dark-semantic-grid: #000; + * } + * :root { + * --dh-color-from-dark-components: #000; + * } + */ export const themeDark = [ themeDarkPalette, themeDarkSemantic, themeDarkSemanticEditor, themeDarkSemanticGrid, + themeDarkComponents, ].join('\n'); export default themeDark; diff --git a/packages/components/src/theme/theme-dark/theme-dark-components.css b/packages/components/src/theme/theme-dark/theme-dark-components.css new file mode 100644 index 0000000000..ce3946b392 --- /dev/null +++ b/packages/components/src/theme/theme-dark/theme-dark-components.css @@ -0,0 +1,6 @@ +/* stylelint-disable alpha-value-notation */ +:root { + --dh-color-quickactions-bg: hsla(var(--dh-color-gray-hue), 0%, 11%, 0.9); + --dh-color-radial-reaction: hsla(var(--dh-color-gray-hue), 0%, 92%, 0.6); + --dh-color-colorpicker-border: hsla(var(--dh-color-gray-hue), 0%, 94%, 0.1); +} diff --git a/packages/components/src/theme/theme-dark/theme-dark-semantic.css b/packages/components/src/theme/theme-dark/theme-dark-semantic.css index f3a003352f..364e2cb75e 100644 --- a/packages/components/src/theme/theme-dark/theme-dark-semantic.css +++ b/packages/components/src/theme/theme-dark/theme-dark-semantic.css @@ -36,6 +36,22 @@ --dh-color-accent-background-down: var(--dh-color-accent-400); --dh-color-accent-background-key-focus: var(--dh-color-accent-500); + /* Background Defaults */ + --dh-color-default-gray-bg: var(--dh-color-gray-700); + --dh-color-default-blue-bg: var(--dh-color-blue-700); + --dh-color-default-red-bg: var(--dh-color-red-700); + --dh-color-default-orange-bg: var(--dh-color-orange-800); + --dh-color-default-yellow-bg: var(--dh-color-yellow-1000); + --dh-color-default-chartreuse-bg: var(--dh-color-chartreuse-900); + --dh-color-default-celery-bg: var(--dh-color-celery-800); + --dh-color-default-green-bg: var(--dh-color-green-700); + --dh-color-default-seafoam-bg: var(--dh-color-seafoam-700); + --dh-color-default-cyan-bg: var(--dh-color-cyan-700); + --dh-color-default-indigo-bg: var(--dh-color-indigo-700); + --dh-color-default-purple-bg: var(--dh-color-purple-700); + --dh-color-default-fuchsia-bg: var(--dh-color-fuchsia-700); + --dh-color-default-magenta-bg: var(--dh-color-magenta-700); + /* Focus */ --dh-color-focus: var(--dh-color-blue-800); --dh-color-focus-border: var(--dh-color-blue-800); @@ -53,11 +69,45 @@ 0.2 ); + /* Shadows / Overlays */ + --dh-color-dropshadow: hsla(var(--dh-color-gray-hue), 0, 0, 0.8); + --dh-color-overlay-modal-bg: hsla(var(--dh-color-gray-hue), 0%, 0%, 0.6); + --dh-color-overlay-hover-bg: hsla(var(--dh-color-gray-hue), 0%, 100%, 0.08); + /* Negative Background */ - --dh-color-negative-background-default: var(--dh-color-red-600); - --dh-color-negative-background-hover: var(--dh-color-red-500); - --dh-color-negative-background-down: var(--dh-color-red-400); - --dh-color-negative-background-key-focus: var(--dh-color-red-500); + --dh-color-negative-default-bg: var(--dh-color-red-600); + --dh-color-negative-hover-bg: var(--dh-color-red-500); + --dh-color-negative-down-bg: var(--dh-color-red-400); + --dh-color-negative-key-focus-bg: var(--dh-color-red-500); + + /* Neutral */ + --dh-neutral-default-bg: var(--dh-color-gray-500); + --dh-neutral-hover-bg: var(--dh-color-gray-400); + --dh-neutral-down-bg: var(--dh-color-gray-300); + --dh-neutral-key-focus-bg: var(--dh-color-gray-400); + + --dh-neutral-subdued-default-bg: var(--dh-color-gray-400); + --dh-neutral-subdued-hover-bg: var(--dh-color-gray-300); + --dh-neutral-subdued-down-bg: var(--dh-color-gray-200); + --dh-neutral-subdued-key-focus-bg: var(--dh-color-gray-300); + + /* Positive */ + --dh-color-positive-default-bg: var(--dh-color-green-900); + --dh-color-positive-hover-bg: var(--dh-color-green-800); + --dh-color-positive-down-bg: var(--dh-color-green-700); + --dh-color-positive-key-focus-bg: var(--dh-color-green-800); + + /* Informative */ + --dh-color-info-default-bg: var(--dh-color-cyan-1000); + --dh-color-info-hover-bg: var(--dh-color-cyan-900); + --dh-color-info-down-bg: var(--dh-color-cyan-800); + --dh-color-info-key-focus-bg: var(--dh-color-cyan-900); + + /* Notice */ + --dh-color-notice-default-bg: var(--dh-color-yellow-1000); + --dh-color-notice-hover-bg: var(--dh-color-yellow-900); + --dh-color-notice-down-bg: var(--dh-color-yellow-800); + --dh-color-notice-key-focus-bg: var(--dh-color-yellow-1000); /* Visual Colors */ --dh-color-visual-blue: var(--dh-color-blue-700); @@ -78,4 +128,9 @@ --dh-color-visual-positive: var(--dh-color-green-1100); --dh-color-visual-negative: var(--dh-color-red-800); --dh-color-visual-notice: var(--dh-color-yellow-1200); + --dh-color-visual-info: var(--dh-color-cyan-1100); + + /* Wells */ + --dh-color-well-bg: hsla(var(--dh-color-gray-hue) 0% 92% 0.02); + --dh-color-well-border: hsla(var(--dh-color-gray-hue) 0% 94% 0.05); } diff --git a/packages/components/src/theme/theme-spectrum/index.ts b/packages/components/src/theme/theme-spectrum/index.ts new file mode 100644 index 0000000000..1b5405e786 --- /dev/null +++ b/packages/components/src/theme/theme-spectrum/index.ts @@ -0,0 +1,22 @@ +import palette from './theme-spectrum-palette.module.css'; +import alias from './theme-spectrum-alias.module.css'; +import overrides from './theme-spectrum-overrides.module.css'; + +/** + * Spectrum theme variables are exported as a map of css class names. The keys + * come from css classes in the imported css modules. The values are generated + * by Vite. + * + * e.g. + * { + * 'dh-spectrum-palette': '_dh-spectrum-palette_abr16_1', + * 'dh-spectrum-alias': '_dh-spectrum-alias_18mbe_1', + * } + */ +export const themeSpectrumClassesCommon = { + ...palette, + ...alias, + ...overrides, +}; + +export default themeSpectrumClassesCommon; diff --git a/packages/components/src/theme/theme-spectrum/theme-spectrum-alias.module.css b/packages/components/src/theme/theme-spectrum/theme-spectrum-alias.module.css new file mode 100644 index 0000000000..753596c72a --- /dev/null +++ b/packages/components/src/theme/theme-spectrum/theme-spectrum-alias.module.css @@ -0,0 +1,206 @@ +/* stylelint-disable custom-property-empty-line-before */ +/* stylelint-disable alpha-value-notation */ +.dh-spectrum-alias { + --spectrum-alias-background-color-default: var(--dh-color-background); + + /* Shadows / Overlays */ + --spectrum-alias-dropshadow-color: var(--dh-color-dropshadow); + --spectrum-alias-background-color-modal-overlay: var( + --dh-color-modal-overlay-bg + ); + --spectrum-alias-background-color-hover-overlay: var( + --dh-color-overlay-hover-bg + ); + + /* Color Picker Borders */ + --spectrum-colorarea-border-color: var(--dh-color-colorpicker-border); + --spectrum-colorarea-border-color-hover: var(--dh-color-colorpicker-border); + --spectrum-colorarea-border-color-down: var(--dh-color-colorpicker-border); + --spectrum-colorarea-border-color-key-focus: var( + --dh-color-colorpicker-border + ); + --spectrum-colorslider-border-color: var(--dh-color-colorpicker-border); + --spectrum-colorslider-border-color-hover: var(--dh-color-colorpicker-border); + --spectrum-colorslider-border-color-down: var(--dh-color-colorpicker-border); + --spectrum-colorslider-border-color-key-focus: var( + --dh-color-colorpicker-border + ); + --spectrum-colorslider-vertical-border-color: var( + --dh-color-colorpicker-border + ); + --spectrum-colorslider-vertical-border-color-hover: var( + --dh-color-colorpicker-border + ); + --spectrum-colorslider-vertical-border-color-down: var( + --dh-color-colorpicker-border + ); + --spectrum-colorslider-vertical-border-color-key-focus: var( + --dh-color-colorpicker-border + ); + --spectrum-colorwheel-border-color: var(--dh-color-colorpicker-border); + --spectrum-colorwheel-border-color-hover: var(--dh-color-colorpicker-border); + --spectrum-colorwheel-border-color-down: var(--dh-color-colorpicker-border); + --spectrum-colorwheel-border-color-key-focus: var( + --dh-color-colorpicker-border + ); + + /* Highlight */ + --spectrum-alias-highlight-active: var(--dh-color-highlight-active); + --spectrum-alias-highlight-hover: var(--dh-color-highlight-hover); + --spectrum-alias-highlight-invalid: var(--dh-color-highlight-invalid); + --spectrum-alias-highlight-selected: var(--dh-color-highlight-selected); + --spectrum-alias-highlight-selected-hover: var( + --dh-color-highlight-selected-hover + ); + + --spectrum-alias-text-highlight-color: var(--dh-color-text-highlight); + --spectrum-alias-background-color-quickactions: var( + --dh-color-quickactions-bg + ); + --spectrum-alias-radial-reaction-color-default: var( + --dh-color-radial-reaction + ); + + --spectrum-alias-appframe-border-color: var(--spectrum-global-color-gray-50); + --spectrum-alias-appframe-separator-color: var( + --spectrum-global-color-gray-50 + ); + --spectrum-alias-pasteboard-background-color: var( + --spectrum-global-color-gray-50 + ); + + /* Tabs */ + --spectrum-tabs-compact-selection-indicator-color: var( + --spectrum-global-color-blue-500 + ); + --spectrum-tabs-compact-vertical-rule-color: var( + --spectrum-global-color-gray-200 + ); + --spectrum-tabs-compact-vertical-emphasized-selection-indicator-color: var( + --spectrum-global-color-blue-500 + ); + --spectrum-tabs-compact-vertical-emphasized-rule-color: var( + --spectrum-global-color-gray-200 + ); + --spectrum-tabs-emphasized-selection-indicator-color: var( + --spectrum-global-color-blue-500 + ); + --spectrum-tabs-quiet-compact-emphasized-selection-indicator-color: var( + --spectrum-global-color-blue-500 + ); + --spectrum-tabs-quiet-compact-vertical-emphasized-selection-indicator-color: var( + --spectrum-global-color-blue-500 + ); + --spectrum-tabs-quiet-emphasized-selection-indicator-color: var( + --spectrum-global-color-blue-500 + ); + --spectrum-tabs-quiet-vertical-emphasized-selection-indicator-color: var( + --spectrum-global-color-blue-500 + ); + + /* Wells */ + --spectrum-well-background-color: var(--dh-color-well-bg); + --spectrum-well-border-color: var(--dh-color-well-border); + + /* PATCH: This is missing in Spectrum css */ + --spectrum-tray-background-color: var(--spectrum-global-color-gray-100); + + --react-spectrum-datepicker-placeholder-color: var( + --spectrum-global-color-gray-600 + ); /* 4.8:1 contrast ratio */ + + /* Accent */ + --spectrum-accent-background-color-default: var( + --dh-color-accent-background-default + ); + --spectrum-accent-background-color-hover: var( + --dh-color-accent-background-hover + ); + --spectrum-accent-background-color-down: var( + --dh-color-accent-background-down + ); + --spectrum-accent-background-color-key-focus: var( + --dh-color-accent-background-key-focus + ); + + /* Neutral */ + --spectrum-neutral-background-color-default: var(--dh-neutral-default-bg); + --spectrum-neutral-background-color-hover: var(--dh-neutral-hover-bg); + --spectrum-neutral-background-color-down: var(--dh-neutral-down-bg); + --spectrum-neutral-background-color-key-focus: var(--dh-neutral-key-focus-bg); + + --spectrum-neutral-subdued-background-color-default: var( + --dh-neutral-subdued-default-bg + ); + --spectrum-neutral-subdued-background-color-hover: var( + --dh-neutral-subdued-hover-bg + ); + --spectrum-neutral-subdued-background-color-down: var( + --dh-neutral-subdued-down-bg + ); + --spectrum-neutral-subdued-background-color-key-focus: var( + --dh-neutral-subdued-key-focus-bg + ); + + /* Negative */ + --spectrum-negative-background-color-default: var( + --dh-color-negative-default-bg + ); + --spectrum-negative-background-color-hover: var(--dh-color-negative-hover-bg); + --spectrum-negative-background-color-down: var(--dh-color-negative-down-bg); + --spectrum-negative-background-color-key-focus: var( + --dh-color-negative-key-focus-bg + ); + + /* Positive */ + --spectrum-positive-background-color-default: var( + --dh-color-positive-default-bg + ); + --spectrum-positive-background-color-hover: var(--dh-color-positive-hover-bg); + --spectrum-positive-background-color-down: var(--dh-color-positive-down-bg); + --spectrum-positive-background-color-key-focus: var( + --dh-color-positive-key-focus-bg + ); + + /* Informative */ + --spectrum-informative-background-color-default: var( + --dh-color-info-default-bg + ); + --spectrum-informative-background-color-hover: var(--dh-color-info-hover-bg); + --spectrum-informative-background-color-down: var(--dh-color-info-down-bg); + --spectrum-informative-background-color-key-focus: var( + --dh-color-info-key-focus-bg + ); + + /* Notice */ + --spectrum-notice-background-color-default: var(--dh-color-notice-default-bg); + --spectrum-notice-background-color-hover: var(--dh-color-notice-hover-bg); + --spectrum-notice-background-color-down: var(--dh-color-notice-down-bg); + --spectrum-notice-background-color-key-focus: var( + --dh-color-notice-key-focus-bg + ); + + /* Default Background */ + --spectrum-gray-background-color-default: var(--dh-color-default-gray-bg); + --spectrum-red-background-color-default: var(--dh-color-default-red-bg); + --spectrum-orange-background-color-default: var(--dh-color-default-orange-bg); + --spectrum-yellow-background-color-default: var(--dh-color-default-yellow-bg); + --spectrum-chartreuse-background-color-default: var( + --dh-color-default-chartreuse-bg + ); + --spectrum-celery-background-color-default: var(--dh-color-default-celery-bg); + --spectrum-green-background-color-default: var(--dh-color-default-green-bg); + --spectrum-seafoam-background-color-default: var( + --dh-color-default-seafoam-bg + ); + --spectrum-cyan-background-color-default: var(--dh-color-default-cyan-bg); + --spectrum-blue-background-color-default: var(--dh-color-default-blue-bg); + --spectrum-indigo-background-color-default: var(--dh-color-default-indigo-bg); + --spectrum-purple-background-color-default: var(--dh-color-default-purple-bg); + --spectrum-fuchsia-background-color-default: var( + --dh-color-default-fuchsia-bg + ); + --spectrum-magenta-background-color-default: var( + --dh-color-default-magenta-bg + ); +} diff --git a/packages/components/src/theme/theme-spectrum/theme-spectrum-overrides.module.css b/packages/components/src/theme/theme-spectrum/theme-spectrum-overrides.module.css new file mode 100644 index 0000000000..c701ac4739 --- /dev/null +++ b/packages/components/src/theme/theme-spectrum/theme-spectrum-overrides.module.css @@ -0,0 +1,5 @@ +[class^='spectrum'] { + /* --font-family-sans-serif is defined in Bootstrap's _root.scss. We want + Spectrum to use the same default font-family */ + font-family: var(--font-family-sans-serif) !important; +} diff --git a/packages/components/src/theme/theme-spectrum/theme-spectrum-palette.module.css b/packages/components/src/theme/theme-spectrum/theme-spectrum-palette.module.css new file mode 100644 index 0000000000..542d5bb60f --- /dev/null +++ b/packages/components/src/theme/theme-spectrum/theme-spectrum-palette.module.css @@ -0,0 +1,222 @@ +.dh-spectrum-palette { + /* Gray */ + --spectrum-gray-50: var(--dh-color-gray-50); + --spectrum-gray-75: var(--dh-color-gray-75); + --spectrum-gray-100: var(--dh-color-gray-100); + --spectrum-gray-200: var(--dh-color-gray-200); + --spectrum-gray-300: var(--dh-color-gray-300); + --spectrum-gray-400: var(--dh-color-gray-400); + --spectrum-gray-500: var(--dh-color-gray-500); + --spectrum-gray-600: var(--dh-color-gray-600); + --spectrum-gray-700: var(--dh-color-gray-700); + --spectrum-gray-800: var(--dh-color-gray-800); + --spectrum-gray-900: var(--dh-color-gray-900); + + /* Blue */ + --spectrum-blue-100: var(--dh-color-blue-100); + --spectrum-blue-200: var(--dh-color-blue-200); + --spectrum-blue-300: var(--dh-color-blue-300); + --spectrum-blue-400: var(--dh-color-blue-400); + --spectrum-blue-500: var(--dh-color-blue-500); + --spectrum-blue-600: var(--dh-color-blue-600); + --spectrum-blue-700: var(--dh-color-blue-700); + --spectrum-blue-800: var(--dh-color-blue-800); + --spectrum-blue-900: var(--dh-color-blue-900); + --spectrum-blue-1000: var(--dh-color-blue-1000); + --spectrum-blue-1100: var(--dh-color-blue-1100); + --spectrum-blue-1200: var(--dh-color-blue-1200); + --spectrum-blue-1300: var(--dh-color-blue-1300); + --spectrum-blue-1400: var(--dh-color-blue-1400); + + /* Red */ + --spectrum-red-100: var(--dh-color-red-100); + --spectrum-red-200: var(--dh-color-red-200); + --spectrum-red-300: var(--dh-color-red-300); + --spectrum-red-400: var(--dh-color-red-400); + --spectrum-red-500: var(--dh-color-red-500); + --spectrum-red-600: var(--dh-color-red-600); + --spectrum-red-700: var(--dh-color-red-700); + --spectrum-red-800: var(--dh-color-red-800); + --spectrum-red-900: var(--dh-color-red-900); + --spectrum-red-1000: var(--dh-color-red-1000); + --spectrum-red-1100: var(--dh-color-red-1100); + --spectrum-red-1200: var(--dh-color-red-1200); + --spectrum-red-1300: var(--dh-color-red-1300); + --spectrum-red-1400: var(--dh-color-red-1400); + + /* Orange */ + --spectrum-orange-100: var(--dh-color-orange-100); + --spectrum-orange-200: var(--dh-color-orange-200); + --spectrum-orange-300: var(--dh-color-orange-300); + --spectrum-orange-400: var(--dh-color-orange-400); + --spectrum-orange-500: var(--dh-color-orange-500); + --spectrum-orange-600: var(--dh-color-orange-600); + --spectrum-orange-700: var(--dh-color-orange-700); + --spectrum-orange-800: var(--dh-color-orange-800); + --spectrum-orange-900: var(--dh-color-orange-900); + --spectrum-orange-1000: var(--dh-color-orange-1000); + --spectrum-orange-1100: var(--dh-color-orange-1100); + --spectrum-orange-1200: var(--dh-color-orange-1200); + --spectrum-orange-1300: var(--dh-color-orange-1300); + --spectrum-orange-1400: var(--dh-color-orange-1400); + + /* Yellow */ + --spectrum-yellow-100: var(--dh-color-yellow-100); + --spectrum-yellow-200: var(--dh-color-yellow-200); + --spectrum-yellow-300: var(--dh-color-yellow-300); + --spectrum-yellow-400: var(--dh-color-yellow-400); + --spectrum-yellow-500: var(--dh-color-yellow-500); + --spectrum-yellow-600: var(--dh-color-yellow-600); + --spectrum-yellow-700: var(--dh-color-yellow-700); + --spectrum-yellow-800: var(--dh-color-yellow-800); + --spectrum-yellow-900: var(--dh-color-yellow-900); + --spectrum-yellow-1000: var(--dh-color-yellow-1000); + --spectrum-yellow-1100: var(--dh-color-yellow-1100); + --spectrum-yellow-1200: var(--dh-color-yellow-1200); + --spectrum-yellow-1300: var(--dh-color-yellow-1300); + --spectrum-yellow-1400: var(--dh-color-yellow-1400); + + /* Chartreuse */ + --spectrum-chartreuse-100: var(--dh-color-chartreuse-100); + --spectrum-chartreuse-200: var(--dh-color-chartreuse-200); + --spectrum-chartreuse-300: var(--dh-color-chartreuse-300); + --spectrum-chartreuse-400: var(--dh-color-chartreuse-400); + --spectrum-chartreuse-500: var(--dh-color-chartreuse-500); + --spectrum-chartreuse-600: var(--dh-color-chartreuse-600); + --spectrum-chartreuse-700: var(--dh-color-chartreuse-700); + --spectrum-chartreuse-800: var(--dh-color-chartreuse-800); + --spectrum-chartreuse-900: var(--dh-color-chartreuse-900); + --spectrum-chartreuse-1000: var(--dh-color-chartreuse-1000); + --spectrum-chartreuse-1100: var(--dh-color-chartreuse-1100); + --spectrum-chartreuse-1200: var(--dh-color-chartreuse-1200); + --spectrum-chartreuse-1300: var(--dh-color-chartreuse-1300); + --spectrum-chartreuse-1400: var(--dh-color-chartreuse-1400); + + /* Celery */ + --spectrum-celery-100: var(--dh-color-celery-100); + --spectrum-celery-200: var(--dh-color-celery-200); + --spectrum-celery-300: var(--dh-color-celery-300); + --spectrum-celery-400: var(--dh-color-celery-400); + --spectrum-celery-500: var(--dh-color-celery-500); + --spectrum-celery-600: var(--dh-color-celery-600); + --spectrum-celery-700: var(--dh-color-celery-700); + --spectrum-celery-800: var(--dh-color-celery-800); + --spectrum-celery-900: var(--dh-color-celery-900); + --spectrum-celery-1000: var(--dh-color-celery-1000); + --spectrum-celery-1100: var(--dh-color-celery-1100); + --spectrum-celery-1200: var(--dh-color-celery-1200); + --spectrum-celery-1300: var(--dh-color-celery-1300); + --spectrum-celery-1400: var(--dh-color-celery-1400); + + /* Green */ + --spectrum-green-100: var(--dh-color-green-100); + --spectrum-green-200: var(--dh-color-green-200); + --spectrum-green-300: var(--dh-color-green-300); + --spectrum-green-400: var(--dh-color-green-400); + --spectrum-green-500: var(--dh-color-green-500); + --spectrum-green-600: var(--dh-color-green-600); + --spectrum-green-700: var(--dh-color-green-700); + --spectrum-green-800: var(--dh-color-green-800); + --spectrum-green-900: var(--dh-color-green-900); + --spectrum-green-1000: var(--dh-color-green-1000); + --spectrum-green-1100: var(--dh-color-green-1100); + --spectrum-green-1200: var(--dh-color-green-1200); + --spectrum-green-1300: var(--dh-color-green-1300); + --spectrum-green-1400: var(--dh-color-green-1400); + + /* Seafoam */ + --spectrum-seafoam-100: var(--dh-color-seafoam-100); + --spectrum-seafoam-200: var(--dh-color-seafoam-200); + --spectrum-seafoam-300: var(--dh-color-seafoam-300); + --spectrum-seafoam-400: var(--dh-color-seafoam-400); + --spectrum-seafoam-500: var(--dh-color-seafoam-500); + --spectrum-seafoam-600: var(--dh-color-seafoam-600); + --spectrum-seafoam-700: var(--dh-color-seafoam-700); + --spectrum-seafoam-800: var(--dh-color-seafoam-800); + --spectrum-seafoam-900: var(--dh-color-seafoam-900); + --spectrum-seafoam-1000: var(--dh-color-seafoam-1000); + --spectrum-seafoam-1100: var(--dh-color-seafoam-1100); + --spectrum-seafoam-1200: var(--dh-color-seafoam-1200); + --spectrum-seafoam-1300: var(--dh-color-seafoam-1300); + --spectrum-seafoam-1400: var(--dh-color-seafoam-1400); + + /* Cyan */ + --spectrum-cyan-100: var(--dh-color-cyan-100); + --spectrum-cyan-200: var(--dh-color-cyan-200); + --spectrum-cyan-300: var(--dh-color-cyan-300); + --spectrum-cyan-400: var(--dh-color-cyan-400); + --spectrum-cyan-500: var(--dh-color-cyan-500); + --spectrum-cyan-600: var(--dh-color-cyan-600); + --spectrum-cyan-700: var(--dh-color-cyan-700); + --spectrum-cyan-800: var(--dh-color-cyan-800); + --spectrum-cyan-900: var(--dh-color-cyan-900); + --spectrum-cyan-1000: var(--dh-color-cyan-1000); + --spectrum-cyan-1100: var(--dh-color-cyan-1100); + --spectrum-cyan-1200: var(--dh-color-cyan-1200); + --spectrum-cyan-1300: var(--dh-color-cyan-1300); + --spectrum-cyan-1400: var(--dh-color-cyan-1400); + + /* Indigo */ + --spectrum-indigo-100: var(--dh-color-indigo-100); + --spectrum-indigo-200: var(--dh-color-indigo-200); + --spectrum-indigo-300: var(--dh-color-indigo-300); + --spectrum-indigo-400: var(--dh-color-indigo-400); + --spectrum-indigo-500: var(--dh-color-indigo-500); + --spectrum-indigo-600: var(--dh-color-indigo-600); + --spectrum-indigo-700: var(--dh-color-indigo-700); + --spectrum-indigo-800: var(--dh-color-indigo-800); + --spectrum-indigo-900: var(--dh-color-indigo-900); + --spectrum-indigo-1000: var(--dh-color-indigo-1000); + --spectrum-indigo-1100: var(--dh-color-indigo-1100); + --spectrum-indigo-1200: var(--dh-color-indigo-1200); + --spectrum-indigo-1300: var(--dh-color-indigo-1300); + --spectrum-indigo-1400: var(--dh-color-indigo-1400); + + /* Purple */ + --spectrum-purple-100: var(--dh-color-purple-100); + --spectrum-purple-200: var(--dh-color-purple-200); + --spectrum-purple-300: var(--dh-color-purple-300); + --spectrum-purple-400: var(--dh-color-purple-400); + --spectrum-purple-500: var(--dh-color-purple-500); + --spectrum-purple-600: var(--dh-color-purple-600); + --spectrum-purple-700: var(--dh-color-purple-700); + --spectrum-purple-800: var(--dh-color-purple-800); + --spectrum-purple-900: var(--dh-color-purple-900); + --spectrum-purple-1000: var(--dh-color-purple-1000); + --spectrum-purple-1100: var(--dh-color-purple-1100); + --spectrum-purple-1200: var(--dh-color-purple-1200); + --spectrum-purple-1300: var(--dh-color-purple-1300); + --spectrum-purple-1400: var(--dh-color-purple-1400); + + /* Fuchsia */ + --spectrum-fuchsia-100: var(--dh-color-fuchsia-100); + --spectrum-fuchsia-200: var(--dh-color-fuchsia-200); + --spectrum-fuchsia-300: var(--dh-color-fuchsia-300); + --spectrum-fuchsia-400: var(--dh-color-fuchsia-400); + --spectrum-fuchsia-500: var(--dh-color-fuchsia-500); + --spectrum-fuchsia-600: var(--dh-color-fuchsia-600); + --spectrum-fuchsia-700: var(--dh-color-fuchsia-700); + --spectrum-fuchsia-800: var(--dh-color-fuchsia-800); + --spectrum-fuchsia-900: var(--dh-color-fuchsia-900); + --spectrum-fuchsia-1000: var(--dh-color-fuchsia-1000); + --spectrum-fuchsia-1100: var(--dh-color-fuchsia-1100); + --spectrum-fuchsia-1200: var(--dh-color-fuchsia-1200); + --spectrum-fuchsia-1300: var(--dh-color-fuchsia-1300); + --spectrum-fuchsia-1400: var(--dh-color-fuchsia-1400); + + /* Magenta */ + --spectrum-magenta-100: var(--dh-color-magenta-100); + --spectrum-magenta-200: var(--dh-color-magenta-200); + --spectrum-magenta-300: var(--dh-color-magenta-300); + --spectrum-magenta-400: var(--dh-color-magenta-400); + --spectrum-magenta-500: var(--dh-color-magenta-500); + --spectrum-magenta-600: var(--dh-color-magenta-600); + --spectrum-magenta-700: var(--dh-color-magenta-700); + --spectrum-magenta-800: var(--dh-color-magenta-800); + --spectrum-magenta-900: var(--dh-color-magenta-900); + --spectrum-magenta-1000: var(--dh-color-magenta-1000); + --spectrum-magenta-1100: var(--dh-color-magenta-1100); + --spectrum-magenta-1200: var(--dh-color-magenta-1200); + --spectrum-magenta-1300: var(--dh-color-magenta-1300); + --spectrum-magenta-1400: var(--dh-color-magenta-1400); +}