[inspector-monitor] Replace jss with Emotion (#1560)

* Setup Emotion

* Fix setup

* Start conversion

* actionList

* actionListHeader

* actionListRows

* actionListHeaderSelector

* actionListItem

* actionListItemTime

* actionListItemSelector

* actionListItemName

* actionListHeaderSearch

* actionListHeaderWrapper

* actionPreview

* Remaining css

* Format

* Propagate Emotion dependencies

* Fix tests

* Remove styling prop

* Remove jss

* Remove themeState

* Use color map as Emotion theme

* Rework theme resolution

* Inline CSS

* Remove usage of className

* Fix warning

* Create large-spoons-yell.md
This commit is contained in:
Nathan Bierema 2023-12-11 23:02:35 -05:00 committed by GitHub
parent b54bc75cbb
commit 158ba2ce12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 609 additions and 685 deletions

View File

@ -0,0 +1,8 @@
---
'@redux-devtools/app': major
'@redux-devtools/inspector-monitor-test-tab': major
'@redux-devtools/inspector-monitor-trace-tab': major
'@redux-devtools/inspector-monitor': major
---
Replace jss with Emotion in inspector-monitor. `@emotion/react` is now a required peer dependency.

View File

@ -24,6 +24,7 @@
}, },
"dependencies": { "dependencies": {
"@babel/polyfill": "^7.12.1", "@babel/polyfill": "^7.12.1",
"@emotion/react": "^11.11.1",
"@redux-devtools/app": "^4.0.1", "@redux-devtools/app": "^4.0.1",
"@redux-devtools/core": "^3.13.2", "@redux-devtools/core": "^3.13.2",
"@redux-devtools/instrument": "^2.1.0", "@redux-devtools/instrument": "^2.1.0",

View File

@ -40,16 +40,14 @@ describe('Chrome extension', function () {
it("should contain inspector monitor's component", async () => { it("should contain inspector monitor's component", async () => {
await delay(1000); await delay(1000);
const val = await driver const val = await driver
.findElement(webdriver.By.xpath('//div[contains(@class, "inspector-")]')) .findElement(webdriver.By.xpath('//div[@data-testid="inspector"]'))
.getText(); .getText();
expect(val).toBeDefined(); expect(val).toBeDefined();
}); });
it('should contain an empty actions list', async () => { it('should contain an empty actions list', async () => {
const val = await driver const val = await driver
.findElement( .findElement(webdriver.By.xpath('//div[@data-testid="actionListRows"]'))
webdriver.By.xpath('//div[contains(@class, "actionListRows-")]'),
)
.getText(); .getText();
expect(val).toBe(''); expect(val).toBe('');
}); });
@ -72,9 +70,7 @@ describe('Chrome extension', function () {
const result = await driver.wait( const result = await driver.wait(
driver driver
.findElement( .findElement(webdriver.By.xpath('//div[@data-testid="actionListRows"]'))
webdriver.By.xpath('//div[contains(@class, "actionListRows-")]'),
)
.getText() .getText()
.then((val) => { .then((val) => {
return actionsPattern.test(val); return actionsPattern.test(val);

View File

@ -89,7 +89,7 @@ describe('DevTools panel for Electron', function () {
it('should contain INIT action', async () => { it('should contain INIT action', async () => {
const element = await driver.wait( const element = await driver.wait(
webdriver.until.elementLocated( webdriver.until.elementLocated(
webdriver.By.xpath('//div[contains(@class, "actionListRows-")]'), webdriver.By.xpath('//div[@data-testid="actionListRows"]'),
), ),
5000, 5000,
'Element not found', 'Element not found',
@ -100,7 +100,7 @@ describe('DevTools panel for Electron', function () {
it("should contain Inspector monitor's component", async () => { it("should contain Inspector monitor's component", async () => {
const val = await driver const val = await driver
.findElement(webdriver.By.xpath('//div[contains(@class, "inspector-")]')) .findElement(webdriver.By.xpath('//div[@data-testid="inspector"]'))
.getText(); .getText();
expect(val).toBeDefined(); expect(val).toBeDefined();
}); });

View File

@ -72,6 +72,7 @@
"@babel/preset-env": "^7.23.5", "@babel/preset-env": "^7.23.5",
"@babel/preset-react": "^7.23.3", "@babel/preset-react": "^7.23.3",
"@babel/preset-typescript": "^7.23.3", "@babel/preset-typescript": "^7.23.3",
"@emotion/react": "^11.11.1",
"@rjsf/core": "^4.2.3", "@rjsf/core": "^4.2.3",
"@testing-library/jest-dom": "^6.1.5", "@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.1.2", "@testing-library/react": "^14.1.2",
@ -115,6 +116,7 @@
"webpack-dev-server": "^4.15.1" "webpack-dev-server": "^4.15.1"
}, },
"peerDependencies": { "peerDependencies": {
"@emotion/react": "^11.0.0",
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"@types/styled-components": "^5.1.34", "@types/styled-components": "^5.1.34",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0",

View File

@ -42,6 +42,7 @@
}, },
"dependencies": { "dependencies": {
"@apollo/server": "^4.9.5", "@apollo/server": "^4.9.5",
"@emotion/react": "^11.11.1",
"@redux-devtools/app": "^4.0.0", "@redux-devtools/app": "^4.0.0",
"@types/react": "^18.2.43", "@types/react": "^18.2.43",
"body-parser": "^1.20.2", "body-parser": "^1.20.2",

View File

@ -10,6 +10,7 @@
"type-check": "tsc --noEmit" "type-check": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.1",
"@redux-devtools/core": "^3.13.2", "@redux-devtools/core": "^3.13.2",
"@redux-devtools/dock-monitor": "^3.0.2", "@redux-devtools/dock-monitor": "^3.0.2",
"@redux-devtools/inspector-monitor": "^4.0.1", "@redux-devtools/inspector-monitor": "^4.0.1",

View File

@ -1,10 +1,7 @@
import React from 'react'; import React from 'react';
import { createDevTools } from '@redux-devtools/core'; import { createDevTools } from '@redux-devtools/core';
import { import { InspectorMonitor, Tab } from '@redux-devtools/inspector-monitor';
InspectorMonitor, import type { Base16ThemeName } from '@redux-devtools/inspector-monitor';
base16Themes,
Tab,
} from '@redux-devtools/inspector-monitor';
import { DockMonitor } from '@redux-devtools/dock-monitor'; import { DockMonitor } from '@redux-devtools/dock-monitor';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import getOptions from './getOptions'; import getOptions from './getOptions';
@ -20,7 +17,7 @@ export const getDevTools = (location: { search: string }) =>
changeMonitorKey="ctrl-m" changeMonitorKey="ctrl-m"
> >
<InspectorMonitor <InspectorMonitor
theme={getOptions(location).theme as keyof typeof base16Themes} theme={getOptions(location).theme as Base16ThemeName}
invertTheme={!getOptions(location).dark} invertTheme={!getOptions(location).dark}
supportImmutable={getOptions(location).supportImmutable} supportImmutable={getOptions(location).supportImmutable}
tabs={(defaultTabs) => tabs={(defaultTabs) =>

View File

@ -60,6 +60,7 @@
"@babel/preset-env": "^7.23.5", "@babel/preset-env": "^7.23.5",
"@babel/preset-react": "^7.23.3", "@babel/preset-react": "^7.23.3",
"@babel/preset-typescript": "^7.23.3", "@babel/preset-typescript": "^7.23.3",
"@emotion/react": "^11.11.1",
"@redux-devtools/core": "^3.14.0", "@redux-devtools/core": "^3.14.0",
"@redux-devtools/inspector-monitor": "^4.1.0", "@redux-devtools/inspector-monitor": "^4.1.0",
"@testing-library/react": "^14.1.2", "@testing-library/react": "^14.1.2",
@ -85,6 +86,7 @@
"typescript": "~5.2.2" "typescript": "~5.2.2"
}, },
"peerDependencies": { "peerDependencies": {
"@emotion/react": "^11.0.0",
"@redux-devtools/inspector-monitor": "^4.0.0", "@redux-devtools/inspector-monitor": "^4.0.0",
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"@types/styled-components": "^5.1.34", "@types/styled-components": "^5.1.34",

View File

@ -47,6 +47,7 @@
"@babel/preset-env": "^7.23.5", "@babel/preset-env": "^7.23.5",
"@babel/preset-react": "^7.23.3", "@babel/preset-react": "^7.23.3",
"@babel/preset-typescript": "^7.23.3", "@babel/preset-typescript": "^7.23.3",
"@emotion/react": "^11.11.1",
"@redux-devtools/core": "^3.14.0", "@redux-devtools/core": "^3.14.0",
"@redux-devtools/inspector-monitor": "^4.1.0", "@redux-devtools/inspector-monitor": "^4.1.0",
"@testing-library/react": "^14.1.2", "@testing-library/react": "^14.1.2",
@ -76,6 +77,7 @@
"typescript": "~5.2.2" "typescript": "~5.2.2"
}, },
"peerDependencies": { "peerDependencies": {
"@emotion/react": "^11.0.0",
"@redux-devtools/inspector-monitor": "^4.0.0", "@redux-devtools/inspector-monitor": "^4.0.0",
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0",

View File

@ -8,6 +8,9 @@ module.exports = {
tsconfigRootDir: __dirname, tsconfigRootDir: __dirname,
project: true, project: true,
}, },
rules: {
'react/no-unknown-property': ['error', { ignore: ['css'] }],
},
}, },
{ {
files: ['demo/**/*.ts', 'demo/**/*.tsx'], files: ['demo/**/*.ts', 'demo/**/*.tsx'],

View File

@ -2,7 +2,8 @@
"presets": [ "presets": [
["@babel/preset-env", { "targets": "defaults", "modules": false }], ["@babel/preset-env", { "targets": "defaults", "modules": false }],
"@babel/preset-react", "@babel/preset-react",
"@babel/preset-typescript" "@babel/preset-typescript",
"@emotion/babel-preset-css-prop"
], ],
"plugins": ["@babel/plugin-transform-runtime"] "plugins": ["@babel/plugin-transform-runtime"]
} }

View File

@ -2,7 +2,8 @@
"presets": [ "presets": [
["@babel/preset-env", { "targets": "defaults" }], ["@babel/preset-env", { "targets": "defaults" }],
"@babel/preset-react", "@babel/preset-react",
"@babel/preset-typescript" "@babel/preset-typescript",
"@emotion/babel-preset-css-prop"
], ],
"plugins": ["@babel/plugin-transform-runtime"] "plugins": ["@babel/plugin-transform-runtime"]
} }

View File

@ -10,6 +10,7 @@
"type-check": "tsc --noEmit" "type-check": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.1",
"@redux-devtools/core": "^3.13.0", "@redux-devtools/core": "^3.13.0",
"@redux-devtools/dock-monitor": "^3.0.0", "@redux-devtools/dock-monitor": "^3.0.0",
"@redux-devtools/inspector-monitor": "^4.0.0", "@redux-devtools/inspector-monitor": "^4.0.0",

View File

@ -1,10 +1,8 @@
import React from 'react'; import React from 'react';
import { createDevTools } from '@redux-devtools/core'; import { createDevTools } from '@redux-devtools/core';
import { DockMonitor } from '@redux-devtools/dock-monitor'; import { DockMonitor } from '@redux-devtools/dock-monitor';
import { import { InspectorMonitor } from '@redux-devtools/inspector-monitor';
InspectorMonitor, import type { Base16ThemeName } from '@redux-devtools/inspector-monitor';
base16Themes,
} from '@redux-devtools/inspector-monitor';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import getOptions from './getOptions'; import getOptions from './getOptions';
@ -32,7 +30,7 @@ export const getDevTools = (location: { search: string }) =>
changeMonitorKey="ctrl-m" changeMonitorKey="ctrl-m"
> >
<InspectorMonitor <InspectorMonitor
theme={getOptions(location).theme as keyof typeof base16Themes} theme={getOptions(location).theme as Base16ThemeName}
invertTheme={!getOptions(location).dark} invertTheme={!getOptions(location).dark}
supportImmutable={getOptions(location).supportImmutable} supportImmutable={getOptions(location).supportImmutable}
tabs={(defaultTabs) => [ tabs={(defaultTabs) => [

View File

@ -47,8 +47,6 @@
"immutable": "^4.3.4", "immutable": "^4.3.4",
"javascript-stringify": "^2.1.0", "javascript-stringify": "^2.1.0",
"jsondiffpatch": "^0.5.0", "jsondiffpatch": "^0.5.0",
"jss": "^10.10.0",
"jss-preset-default": "^10.10.0",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"react-base16-styling": "^0.9.1", "react-base16-styling": "^0.9.1",
"react-json-tree": "^0.18.0", "react-json-tree": "^0.18.0",
@ -62,6 +60,8 @@
"@babel/preset-env": "^7.23.5", "@babel/preset-env": "^7.23.5",
"@babel/preset-react": "^7.23.3", "@babel/preset-react": "^7.23.3",
"@babel/preset-typescript": "^7.23.3", "@babel/preset-typescript": "^7.23.3",
"@emotion/babel-preset-css-prop": "^11.11.0",
"@emotion/react": "^11.11.1",
"@redux-devtools/core": "^3.14.0", "@redux-devtools/core": "^3.14.0",
"@types/dateformat": "^5.0.2", "@types/dateformat": "^5.0.2",
"@types/hex-rgba": "^1.0.3", "@types/hex-rgba": "^1.0.3",
@ -80,6 +80,7 @@
"typescript": "~5.2.2" "typescript": "~5.2.2"
}, },
"peerDependencies": { "peerDependencies": {
"@emotion/react": "^11.0.0",
"@redux-devtools/core": "^3.0.0", "@redux-devtools/core": "^3.0.0",
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0",

View File

@ -1,7 +1,6 @@
import React, { ReactNode, useCallback, useLayoutEffect, useRef } from 'react'; import React, { ReactNode, useCallback, useLayoutEffect, useRef } from 'react';
import { Action } from 'redux'; import { Action } from 'redux';
import { PerformAction } from '@redux-devtools/core'; import { PerformAction } from '@redux-devtools/core';
import { StylingFunction } from 'react-base16-styling';
import { import {
closestCenter, closestCenter,
DndContext, DndContext,
@ -51,7 +50,6 @@ interface Props<A extends Action<string>> {
draggableActions: boolean; draggableActions: boolean;
hideMainButtons: boolean | undefined; hideMainButtons: boolean | undefined;
hideActionButtons: boolean | undefined; hideActionButtons: boolean | undefined;
styling: StylingFunction;
onSearch: (value: string) => void; onSearch: (value: string) => void;
onSelect: (e: React.MouseEvent<HTMLDivElement>, actionId: number) => void; onSelect: (e: React.MouseEvent<HTMLDivElement>, actionId: number) => void;
onToggleAction: (actionId: number) => void; onToggleAction: (actionId: number) => void;
@ -64,7 +62,6 @@ interface Props<A extends Action<string>> {
} }
export default function ActionList<A extends Action<string>>({ export default function ActionList<A extends Action<string>>({
styling,
actions, actions,
actionIds, actionIds,
isWideLayout, isWideLayout,
@ -150,13 +147,29 @@ export default function ActionList<A extends Action<string>>({
<div <div
key="actionList" key="actionList"
data-testid="actionList" data-testid="actionList"
{...styling( css={[
['actionList', isWideLayout && 'actionListWide'], (theme) => ({
isWideLayout, flexBasis: '40%',
)} flexShrink: 0,
overflowX: 'hidden',
overflowY: 'auto',
borderBottomWidth: '3px',
borderBottomStyle: 'double',
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.BACKGROUND_COLOR,
borderColor: theme.LIST_BORDER_COLOR,
}),
isWideLayout && {
flexBasis: '40%',
borderBottom: 'none',
borderRightWidth: '3px',
borderRightStyle: 'double',
},
]}
> >
<ActionListHeader <ActionListHeader
styling={styling}
onSearch={onSearch} onSearch={onSearch}
onCommit={onCommit} onCommit={onCommit}
onSweep={onSweep} onSweep={onSweep}
@ -167,7 +180,7 @@ export default function ActionList<A extends Action<string>>({
/> />
<div <div
data-testid="actionListRows" data-testid="actionListRows"
{...styling('actionListRows')} css={{ overflow: 'auto' }}
ref={setNodeRef} ref={setNodeRef}
> >
<DndContext <DndContext
@ -183,7 +196,6 @@ export default function ActionList<A extends Action<string>>({
{filteredActionIds.map((actionId) => ( {filteredActionIds.map((actionId) => (
<SortableItem key={actionId} actionId={actionId}> <SortableItem key={actionId} actionId={actionId}>
<ActionListRow <ActionListRow
styling={styling}
actionId={actionId} actionId={actionId}
isInitAction={!actionId} isInitAction={!actionId}
isSelected={ isSelected={

View File

@ -1,6 +1,9 @@
import React, { FunctionComponent } from 'react'; import React, { FunctionComponent } from 'react';
import { StylingFunction } from 'react-base16-styling';
import RightSlider from './RightSlider'; import RightSlider from './RightSlider';
import {
selectorButtonCss,
selectorButtonSmallCss,
} from './utils/selectorButtonStyles';
const getActiveButtons = (hasSkippedActions: boolean): ('Sweep' | 'Commit')[] => const getActiveButtons = (hasSkippedActions: boolean): ('Sweep' | 'Commit')[] =>
[hasSkippedActions && 'Sweep', 'Commit'].filter( [hasSkippedActions && 'Sweep', 'Commit'].filter(
@ -8,7 +11,6 @@ const getActiveButtons = (hasSkippedActions: boolean): ('Sweep' | 'Commit')[] =>
); );
interface Props { interface Props {
styling: StylingFunction;
onSearch: (value: string) => void; onSearch: (value: string) => void;
onCommit: () => void; onCommit: () => void;
onSweep: () => void; onSweep: () => void;
@ -19,7 +21,6 @@ interface Props {
} }
const ActionListHeader: FunctionComponent<Props> = ({ const ActionListHeader: FunctionComponent<Props> = ({
styling,
onSearch, onSearch,
hasSkippedActions, hasSkippedActions,
hasStagedActions, hasStagedActions,
@ -28,17 +29,45 @@ const ActionListHeader: FunctionComponent<Props> = ({
hideMainButtons, hideMainButtons,
searchValue, searchValue,
}) => ( }) => (
<div {...styling('actionListHeader')}> <div
css={(theme) => ({
display: 'flex',
flex: '0 0 auto',
alignItems: 'center',
borderBottomWidth: '1px',
borderBottomStyle: 'solid',
borderColor: theme.LIST_BORDER_COLOR,
})}
>
<input <input
{...styling('actionListHeaderSearch')} css={(theme) => ({
outline: 'none',
border: 'none',
width: '100%',
padding: '5px 10px',
fontSize: '1em',
fontFamily: 'monaco, Consolas, "Lucida Console", monospace',
backgroundColor: theme.BACKGROUND_COLOR,
color: theme.TEXT_COLOR,
'&::-webkit-input-placeholder': {
color: theme.TEXT_PLACEHOLDER_COLOR,
},
'&::-moz-placeholder': {
color: theme.TEXT_PLACEHOLDER_COLOR,
},
})}
onChange={(e) => onSearch(e.target.value)} onChange={(e) => onSearch(e.target.value)}
placeholder="filter..." placeholder="filter..."
value={searchValue} value={searchValue}
/> />
{!hideMainButtons && ( {!hideMainButtons && (
<div {...styling('actionListHeaderWrapper')}> <div css={{ position: 'relative', height: '20px' }}>
<RightSlider shown={hasStagedActions} styling={styling}> <RightSlider shown={hasStagedActions}>
<div {...styling('actionListHeaderSelector')}> <div css={{ display: 'inline-flex', marginRight: '10px' }}>
{getActiveButtons(hasSkippedActions).map((btn) => ( {getActiveButtons(hasSkippedActions).map((btn) => (
<div <div
key={btn} key={btn}
@ -48,11 +77,7 @@ const ActionListHeader: FunctionComponent<Props> = ({
Sweep: onSweep, Sweep: onSweep,
})[btn]() })[btn]()
} }
{...styling( css={[selectorButtonCss, selectorButtonSmallCss]}
['selectorButton', 'selectorButtonSmall'],
false,
true,
)}
> >
{btn} {btn}
</div> </div>

View File

@ -2,17 +2,33 @@ import React, { MouseEvent, MouseEventHandler, PureComponent } from 'react';
import dateformat from 'dateformat'; import dateformat from 'dateformat';
import type { DebouncedFunc } from 'lodash'; import type { DebouncedFunc } from 'lodash';
import debounce from 'lodash.debounce'; import debounce from 'lodash.debounce';
import { StylingFunction } from 'react-base16-styling';
import { Action } from 'redux'; import { Action } from 'redux';
import type { Interpolation, Theme } from '@emotion/react';
import RightSlider from './RightSlider'; import RightSlider from './RightSlider';
import {
selectorButtonCss,
selectorButtonSelectedCss,
selectorButtonSmallCss,
} from './utils/selectorButtonStyles';
const BUTTON_SKIP = 'Skip'; const BUTTON_SKIP = 'Skip';
const BUTTON_JUMP = 'Jump'; const BUTTON_JUMP = 'Jump';
type Button = typeof BUTTON_SKIP | typeof BUTTON_JUMP; type Button = typeof BUTTON_SKIP | typeof BUTTON_JUMP;
const actionListItemTimeCss: Interpolation<Theme> = (theme) => ({
display: 'inline',
padding: '4px 6px',
borderRadius: '3px',
fontSize: '0.8em',
lineHeight: '1em',
flexShrink: 0,
backgroundColor: theme.ACTION_TIME_BACK_COLOR,
color: theme.ACTION_TIME_COLOR,
});
interface Props<A extends Action<string>> { interface Props<A extends Action<string>> {
styling: StylingFunction;
actionId: number; actionId: number;
isInitAction: boolean; isInitAction: boolean;
isSelected: boolean; isSelected: boolean;
@ -38,7 +54,6 @@ export default class ActionListRow<
render() { render() {
const { const {
styling,
isSelected, isSelected,
action, action,
actionId, actionId,
@ -74,28 +89,44 @@ export default class ActionListRow<
onMouseDown={this.handleMouseDown} onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseEnter} onMouseUp={this.handleMouseEnter}
data-id={actionId} data-id={actionId}
{...styling( css={[
[ (theme) => ({
'actionListItem', borderBottomWidth: '1px',
isSelected && 'actionListItemSelected', borderBottomStyle: 'solid',
isSkipped && 'actionListItemSkipped', display: 'flex',
isInFuture && 'actionListFromFuture', justifyContent: 'space-between',
], padding: '5px 10px',
isSelected, cursor: 'pointer',
action, userSelect: 'none',
)}
borderBottomColor: theme.BORDER_COLOR,
}),
isSelected &&
((theme) => ({
backgroundColor: theme.SELECTED_BACKGROUND_COLOR,
})),
isSkipped &&
((theme) => ({
backgroundColor: theme.SKIPPED_BACKGROUND_COLOR,
})),
isInFuture && { opacity: '0.6' },
]}
> >
<div <div
{...styling([ css={[
'actionListItemName', {
isSkipped && 'actionListItemNameSkipped', overflow: 'hidden',
])} textOverflow: 'ellipsis',
lineHeight: '20px',
},
isSkipped && { textDecoration: 'line-through', opacity: 0.3 },
]}
> >
{actionType} {actionType}
</div> </div>
{hideActionButtons ? ( {hideActionButtons ? (
<RightSlider styling={styling} shown> <RightSlider shown>
<div {...styling('actionListItemTime')}> <div css={actionListItemTimeCss}>
{timeDelta === 0 {timeDelta === 0
? '+00:00:00' ? '+00:00:00'
: dateformat( : dateformat(
@ -105,9 +136,9 @@ export default class ActionListRow<
</div> </div>
</RightSlider> </RightSlider>
) : ( ) : (
<div {...styling('actionListItemButtons')}> <div css={{ position: 'relative', height: '20px', display: 'flex' }}>
<RightSlider styling={styling} shown={!showButtons} rotate> <RightSlider shown={!showButtons} rotate>
<div {...styling('actionListItemTime')}> <div css={actionListItemTimeCss}>
{timeDelta === 0 {timeDelta === 0
? '+00:00:00' ? '+00:00:00'
: dateformat( : dateformat(
@ -116,23 +147,20 @@ export default class ActionListRow<
)} )}
</div> </div>
</RightSlider> </RightSlider>
<RightSlider styling={styling} shown={showButtons} rotate> <RightSlider shown={showButtons} rotate>
<div {...styling('actionListItemSelector')}> <div css={{ display: 'inline-flex' }}>
{([BUTTON_JUMP, BUTTON_SKIP] as const).map( {([BUTTON_JUMP, BUTTON_SKIP] as const).map(
(btn) => (btn) =>
(!isInitAction || btn !== BUTTON_SKIP) && ( (!isInitAction || btn !== BUTTON_SKIP) && (
<div <div
key={btn} key={btn}
onClick={(e) => this.handleButtonClick(btn, e)} onClick={(e) => this.handleButtonClick(btn, e)}
{...styling( css={[
[ selectorButtonCss,
'selectorButton', isButtonSelected(btn) && selectorButtonSelectedCss,
isButtonSelected(btn) && 'selectorButtonSelected', selectorButtonSmallCss,
'selectorButtonSmall', ]}
], data-isselectorbutton={true}
isButtonSelected(btn),
true,
)}
> >
{btn} {btn}
</div> </div>
@ -177,12 +205,7 @@ export default class ActionListRow<
}, 100); }, 100);
handleMouseDown = (e: MouseEvent<HTMLDivElement>) => { handleMouseDown = (e: MouseEvent<HTMLDivElement>) => {
if ( if ((e.target as HTMLElement).dataset.isselectorbutton) return;
(e.target as unknown as { className: string[] }).className.indexOf(
'selectorButton',
) === 0
)
return;
this.handleMouseLeave(); this.handleMouseLeave();
}; };
} }

View File

@ -1,7 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Base16Theme } from 'redux-devtools-themes'; import { Base16Theme } from 'redux-devtools-themes';
import { Action } from 'redux'; import { Action } from 'redux';
import type { StylingFunction } from 'react-base16-styling';
import type { LabelRenderer } from 'react-json-tree'; import type { LabelRenderer } from 'react-json-tree';
import { PerformAction } from '@redux-devtools/core'; import { PerformAction } from '@redux-devtools/core';
import { Delta } from 'jsondiffpatch'; import { Delta } from 'jsondiffpatch';
@ -13,7 +12,6 @@ import ActionTab from './tabs/ActionTab';
export interface TabComponentProps<S, A extends Action<string>> { export interface TabComponentProps<S, A extends Action<string>> {
labelRenderer: LabelRenderer; labelRenderer: LabelRenderer;
styling: StylingFunction;
computedStates: { state: S; error?: string }[]; computedStates: { state: S; error?: string }[];
actions: { [actionId: number]: PerformAction<A> }; actions: { [actionId: number]: PerformAction<A> };
selectedActionId: number | null; selectedActionId: number | null;
@ -68,7 +66,6 @@ interface Props<S, A extends Action<string>> {
dataTypeKey: string | symbol | undefined; dataTypeKey: string | symbol | undefined;
monitorState: DevtoolsInspectorState; monitorState: DevtoolsInspectorState;
updateMonitorState: (monitorState: Partial<DevtoolsInspectorState>) => void; updateMonitorState: (monitorState: Partial<DevtoolsInspectorState>) => void;
styling: StylingFunction;
onInspectPath: (path: (string | number)[]) => void; onInspectPath: (path: (string | number)[]) => void;
inspectedPath: (string | number)[]; inspectedPath: (string | number)[];
onSelectTab: (tabName: string) => void; onSelectTab: (tabName: string) => void;
@ -85,7 +82,6 @@ class ActionPreview<S, A extends Action<string>> extends Component<
render() { render() {
const { const {
styling,
delta, delta,
error, error,
nextState, nextState,
@ -121,17 +117,34 @@ class ActionPreview<S, A extends Action<string>> extends Component<
renderedTabs.find((tab) => tab.name === DEFAULT_STATE.tabName)!; renderedTabs.find((tab) => tab.name === DEFAULT_STATE.tabName)!;
return ( return (
<div key="actionPreview" {...styling('actionPreview')}> <div
key="actionPreview"
css={(theme) => ({
flex: 1,
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
overflowY: 'hidden',
'& pre': {
border: 'inherit',
borderRadius: '3px',
lineHeight: 'inherit',
color: 'inherit',
},
backgroundColor: theme.BACKGROUND_COLOR,
})}
>
<ActionPreviewHeader <ActionPreviewHeader
tabs={renderedTabs as unknown as Tab<unknown, Action<string>>[]} tabs={renderedTabs as unknown as Tab<unknown, Action<string>>[]}
{...{ styling, inspectedPath, onInspectPath, tabName, onSelectTab }} {...{ inspectedPath, onInspectPath, tabName, onSelectTab }}
/> />
{!error && ( {!error && (
<div key="actionPreviewContent" {...styling('actionPreviewContent')}> <div key="actionPreviewContent" css={{ flex: 1, overflowY: 'auto' }}>
<TabComponent <TabComponent
labelRenderer={this.labelRenderer} labelRenderer={this.labelRenderer}
{...{ {...{
styling,
computedStates, computedStates,
actions, actions,
selectedActionId, selectedActionId,
@ -151,19 +164,40 @@ class ActionPreview<S, A extends Action<string>> extends Component<
/> />
</div> </div>
)} )}
{error && <div {...styling('stateError')}>{error}</div>} {error && (
<div
css={(theme) => ({
padding: '10px',
marginLeft: '14px',
fontWeight: 'bold',
color: theme.ERROR_COLOR,
})}
>
{error}
</div>
)}
</div> </div>
); );
} }
labelRenderer: LabelRenderer = ([key, ...rest], nodeType, expanded) => { labelRenderer: LabelRenderer = ([key, ...rest], nodeType, expanded) => {
const { styling, onInspectPath, inspectedPath } = this.props; const { onInspectPath, inspectedPath } = this.props;
return ( return (
<span> <span>
<span {...styling('treeItemKey')}>{key}</span> <span>{key}</span>
<span <span
{...styling('treeItemPin')} css={(theme) => ({
fontSize: '0.7em',
paddingLeft: '5px',
cursor: 'pointer',
'&:hover': {
textDecoration: 'underline',
},
color: theme.PIN_COLOR,
})}
onClick={() => onClick={() =>
onInspectPath([ onInspectPath([
...inspectedPath.slice(0, inspectedPath.length - 1), ...inspectedPath.slice(0, inspectedPath.length - 1),

View File

@ -1,11 +1,30 @@
import React, { FunctionComponent } from 'react'; import React, { FunctionComponent } from 'react';
import { Action } from 'redux'; import { Action } from 'redux';
import { StylingFunction } from 'react-base16-styling'; import { css } from '@emotion/react';
import type { Interpolation, Theme } from '@emotion/react';
import { Tab } from './ActionPreview'; import { Tab } from './ActionPreview';
import {
selectorButtonCss,
selectorButtonSelectedCss,
} from './utils/selectorButtonStyles';
const inspectedPathKeyCss = css({
'&:not(:last-child):after': {
content: '" > "',
},
});
const inspectedPathKeyLinkCss: Interpolation<Theme> = (theme) => ({
cursor: 'pointer',
color: theme.LINK_COLOR,
'&:hover': {
textDecoration: 'underline',
color: theme.LINK_HOVER_COLOR,
},
});
interface Props<S, A extends Action<string>> { interface Props<S, A extends Action<string>> {
tabs: Tab<S, A>[]; tabs: Tab<S, A>[];
styling: StylingFunction;
inspectedPath: (string | number)[]; inspectedPath: (string | number)[];
onInspectPath: (path: (string | number)[]) => void; onInspectPath: (path: (string | number)[]) => void;
tabName: string; tabName: string;
@ -14,32 +33,38 @@ interface Props<S, A extends Action<string>> {
const ActionPreviewHeader: FunctionComponent< const ActionPreviewHeader: FunctionComponent<
Props<unknown, Action<string>> Props<unknown, Action<string>>
> = ({ styling, inspectedPath, onInspectPath, tabName, onSelectTab, tabs }) => ( > = ({ inspectedPath, onInspectPath, tabName, onSelectTab, tabs }) => (
<div key="previewHeader" {...styling('previewHeader')}> <div
<div {...styling('tabSelector')}> key="previewHeader"
css={(theme) => ({
flex: '0 0 30px',
padding: '5px 10px',
alignItems: 'center',
borderBottomWidth: '1px',
borderBottomStyle: 'solid',
backgroundColor: theme.HEADER_BACKGROUND_COLOR,
borderBottomColor: theme.HEADER_BORDER_COLOR,
})}
>
<div css={{ position: 'relative', display: 'inline-flex', float: 'right' }}>
{tabs.map((tab) => ( {tabs.map((tab) => (
<div <div
onClick={() => onSelectTab(tab.name)} onClick={() => onSelectTab(tab.name)}
key={tab.name} key={tab.name}
{...styling( css={[
[ selectorButtonCss,
'selectorButton', tab.name === tabName && selectorButtonSelectedCss,
tab.name === tabName && 'selectorButtonSelected', ]}
],
tab.name === tabName,
)}
> >
{tab.name} {tab.name}
</div> </div>
))} ))}
</div> </div>
<div {...styling('inspectedPath')}> <div css={{ padding: '6px 0' }}>
{inspectedPath.length ? ( {inspectedPath.length ? (
<span {...styling('inspectedPathKey')}> <span css={inspectedPathKeyCss}>
<a <a onClick={() => onInspectPath([])} css={inspectedPathKeyLinkCss}>
onClick={() => onInspectPath([])}
{...styling('inspectedPathKeyLink')}
>
{tabName} {tabName}
</a> </a>
</span> </span>
@ -50,10 +75,10 @@ const ActionPreviewHeader: FunctionComponent<
idx === inspectedPath.length - 1 ? ( idx === inspectedPath.length - 1 ? (
<span key={key}>{key}</span> <span key={key}>{key}</span>
) : ( ) : (
<span key={key} {...styling('inspectedPathKey')}> <span key={key} css={inspectedPathKeyCss}>
<a <a
onClick={() => onInspectPath(inspectedPath.slice(0, idx + 1))} onClick={() => onInspectPath(inspectedPath.slice(0, idx + 1))}
{...styling('inspectedPathKeyLink')} css={inspectedPathKeyLinkCss}
> >
{key} {key}
</a> </a>

View File

@ -1,10 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Base16Theme } from 'redux-devtools-themes'; import { Base16Theme } from 'redux-devtools-themes';
import {
getBase16Theme,
invertTheme,
StylingFunction,
} from 'react-base16-styling';
import { import {
ActionCreators, ActionCreators,
LiftedAction, LiftedAction,
@ -13,9 +8,10 @@ import {
import { Action, Dispatch } from 'redux'; import { Action, Dispatch } from 'redux';
import { Delta, DiffContext } from 'jsondiffpatch'; import { Delta, DiffContext } from 'jsondiffpatch';
import { import {
createStylingFromTheme, createInspectorMonitorThemeFromBase16Theme,
base16Themes, resolveBase16Theme,
} from './utils/createStylingFromTheme'; } from './utils/themes';
import type { Base16ThemeName } from './utils/themes';
import ActionList from './ActionList'; import ActionList from './ActionList';
import ActionPreview, { Tab } from './ActionPreview'; import ActionPreview, { Tab } from './ActionPreview';
import getInspectedState from './utils/getInspectedState'; import getInspectedState from './utils/getInspectedState';
@ -26,6 +22,7 @@ import {
reducer, reducer,
updateMonitorState, updateMonitorState,
} from './redux'; } from './redux';
import { ThemeProvider } from '@emotion/react';
const { const {
// eslint-disable-next-line @typescript-eslint/unbound-method // eslint-disable-next-line @typescript-eslint/unbound-method
@ -125,17 +122,6 @@ function createIntermediateState<S, A extends Action<string>>(
}; };
} }
function createThemeState<S, A extends Action<string>>(
props: DevtoolsInspectorProps<S, A>,
) {
const base16Theme = getBase16Theme(props.theme, base16Themes)!;
const theme = props.invertTheme ? invertTheme(props.theme) : props.theme;
const styling = createStylingFromTheme(theme);
return { base16Theme, styling };
}
export interface ExternalProps<S, A extends Action<string>> { export interface ExternalProps<S, A extends Action<string>> {
dispatch: Dispatch< dispatch: Dispatch<
DevtoolsInspectorAction | LiftedAction<S, A, DevtoolsInspectorState> DevtoolsInspectorAction | LiftedAction<S, A, DevtoolsInspectorState>
@ -143,7 +129,7 @@ export interface ExternalProps<S, A extends Action<string>> {
preserveScrollTop?: boolean; preserveScrollTop?: boolean;
draggableActions: boolean; draggableActions: boolean;
select: (state: S) => unknown; select: (state: S) => unknown;
theme: keyof typeof base16Themes | Base16Theme; theme: Base16ThemeName | Base16Theme;
supportImmutable: boolean; supportImmutable: boolean;
diffObjectHash?: (item: unknown, index: number) => string; diffObjectHash?: (item: unknown, index: number) => string;
diffPropertyFilter?: (name: string, context: DiffContext) => boolean; diffPropertyFilter?: (name: string, context: DiffContext) => boolean;
@ -160,7 +146,7 @@ interface DefaultProps {
select: (state: unknown) => unknown; select: (state: unknown) => unknown;
supportImmutable: boolean; supportImmutable: boolean;
draggableActions: boolean; draggableActions: boolean;
theme: keyof typeof base16Themes; theme: Base16ThemeName;
invertTheme: boolean; invertTheme: boolean;
} }
@ -172,7 +158,7 @@ export interface DevtoolsInspectorProps<S, A extends Action<string>>
preserveScrollTop?: boolean; preserveScrollTop?: boolean;
draggableActions: boolean; draggableActions: boolean;
select: (state: S) => unknown; select: (state: S) => unknown;
theme: keyof typeof base16Themes | Base16Theme; theme: Base16ThemeName | Base16Theme;
supportImmutable: boolean; supportImmutable: boolean;
diffObjectHash?: (item: unknown, index: number) => string; diffObjectHash?: (item: unknown, index: number) => string;
diffPropertyFilter?: (name: string, context: DiffContext) => boolean; diffPropertyFilter?: (name: string, context: DiffContext) => boolean;
@ -191,7 +177,6 @@ interface State<S, A extends Action<string>> {
action: A; action: A;
error: string | undefined; error: string | undefined;
isWideLayout: boolean; isWideLayout: boolean;
themeState: { base16Theme: Base16Theme; styling: StylingFunction };
} }
class DevtoolsInspector<S, A extends Action<string>> extends PureComponent< class DevtoolsInspector<S, A extends Action<string>> extends PureComponent<
@ -201,7 +186,6 @@ class DevtoolsInspector<S, A extends Action<string>> extends PureComponent<
state: State<S, A> = { state: State<S, A> = {
...createIntermediateState(this.props, this.props.monitorState), ...createIntermediateState(this.props, this.props.monitorState),
isWideLayout: false, isWideLayout: false,
themeState: createThemeState(this.props),
}; };
static update = reducer; static update = reducer;
@ -257,13 +241,6 @@ class DevtoolsInspector<S, A extends Action<string>> extends PureComponent<
) { ) {
this.setState(createIntermediateState(nextProps, nextMonitorState)); this.setState(createIntermediateState(nextProps, nextMonitorState));
} }
if (
this.props.theme !== nextProps.theme ||
this.props.invertTheme !== nextProps.invertTheme
) {
this.setState({ themeState: createThemeState(nextProps) });
}
} }
inspectorCreateRef: React.RefCallback<HTMLDivElement> = (node) => { inspectorCreateRef: React.RefCallback<HTMLDivElement> = (node) => {
@ -277,6 +254,7 @@ class DevtoolsInspector<S, A extends Action<string>> extends PureComponent<
computedStates, computedStates,
draggableActions, draggableActions,
tabs, tabs,
theme,
invertTheme, invertTheme,
skippedActionIds, skippedActionIds,
currentStateIndex, currentStateIndex,
@ -291,19 +269,35 @@ class DevtoolsInspector<S, A extends Action<string>> extends PureComponent<
monitorState; monitorState;
const inspectedPathType = const inspectedPathType =
tabName === 'Action' ? 'inspectedActionPath' : 'inspectedStatePath'; tabName === 'Action' ? 'inspectedActionPath' : 'inspectedStatePath';
const { themeState, isWideLayout, action, nextState, delta, error } = const { isWideLayout, action, nextState, delta, error } = this.state;
this.state;
const { base16Theme, styling } = themeState;
const base16Theme = resolveBase16Theme(theme)!;
const inspectorMonitorTheme = createInspectorMonitorThemeFromBase16Theme(
base16Theme,
invertTheme,
);
return ( return (
<ThemeProvider theme={inspectorMonitorTheme}>
<div <div
key="inspector" key="inspector"
data-testid="inspector" data-testid="inspector"
ref={this.inspectorCreateRef} ref={this.inspectorCreateRef}
{...styling( css={[
['inspector', isWideLayout && 'inspectorWide'], (theme) => ({
isWideLayout, display: 'flex',
)} flexDirection: 'column',
width: '100%',
height: '100%',
fontFamily: 'monaco, Consolas, "Lucida Console", monospace',
fontSize: '12px',
WebkitFontSmoothing: 'antialiased',
lineHeight: '1.5em',
backgroundColor: theme.BACKGROUND_COLOR,
color: theme.TEXT_COLOR,
}),
isWideLayout && { flexDirection: 'row' },
]}
> >
<ActionList <ActionList
{...{ {...{
@ -317,7 +311,6 @@ class DevtoolsInspector<S, A extends Action<string>> extends PureComponent<
draggableActions, draggableActions,
hideMainButtons, hideMainButtons,
hideActionButtons, hideActionButtons,
styling,
}} }}
onSearch={this.handleSearch} onSearch={this.handleSearch}
onSelect={this.handleSelectAction} onSelect={this.handleSelectAction}
@ -350,7 +343,6 @@ class DevtoolsInspector<S, A extends Action<string>> extends PureComponent<
}} }}
monitorState={this.props.monitorState} monitorState={this.props.monitorState}
updateMonitorState={this.updateMonitorState} updateMonitorState={this.updateMonitorState}
styling={styling}
onInspectPath={(path: (string | number)[]) => onInspectPath={(path: (string | number)[]) =>
this.handleInspectPath(inspectedPathType, path) this.handleInspectPath(inspectedPathType, path)
} }
@ -358,6 +350,7 @@ class DevtoolsInspector<S, A extends Action<string>> extends PureComponent<
onSelectTab={this.handleSelectTab} onSelectTab={this.handleSelectTab}
/> />
</div> </div>
</ThemeProvider>
); );
} }

View File

@ -1,26 +1,35 @@
import React, { FunctionComponent } from 'react'; import React, { FunctionComponent } from 'react';
import { StylingFunction } from 'react-base16-styling';
interface Props { interface Props {
styling: StylingFunction;
shown?: boolean; shown?: boolean;
children: React.ReactNode; children: React.ReactNode;
rotate?: boolean; rotate?: boolean;
} }
const RightSlider: FunctionComponent<Props> = ({ const RightSlider: FunctionComponent<Props> = ({ shown, children, rotate }) => (
styling,
shown,
children,
rotate,
}) => (
<div <div
{...styling([ css={[
'rightSlider', {
shown && 'rightSliderShown', WebkitFontSmoothing: 'subpixel-antialiased', // http://stackoverflow.com/a/21136111/4218591
rotate && 'rightSliderRotate', position: 'absolute',
rotate && shown && 'rightSliderRotateShown', right: 0,
])} transform: 'translateX(150%)',
transition: 'transform 0.2s ease-in-out',
},
shown && {
position: 'static',
transform: 'translateX(0)',
},
rotate && {
transform: 'rotateX(90deg)',
transition: 'transform 0.2s ease-in-out 0.08s',
},
rotate &&
shown && {
transform: 'rotateX(0)',
transition: 'transform 0.2s ease-in-out 0.18s',
},
]}
> >
{children} {children}
</div> </div>

View File

@ -1,9 +1,8 @@
export type { StylingFunction } from 'react-base16-styling';
export type { LabelRenderer } from 'react-json-tree'; export type { LabelRenderer } from 'react-json-tree';
export { default as InspectorMonitor } from './DevtoolsInspector'; export { default as InspectorMonitor } from './DevtoolsInspector';
export type { Tab, TabComponentProps } from './ActionPreview'; export type { Tab, TabComponentProps } from './ActionPreview';
export type { DevtoolsInspectorState } from './redux'; export type { DevtoolsInspectorState } from './redux';
export { base16Themes } from './utils/createStylingFromTheme'; export type { Base16ThemeName } from './utils/themes';
export * as inspectorThemes from './themes/index'; export * as inspectorThemes from './themes/index';
export { default as ActionTab } from './tabs/ActionTab'; export { default as ActionTab } from './tabs/ActionTab';
export { default as DiffTab } from './tabs/DiffTab'; export { default as DiffTab } from './tabs/DiffTab';

View File

@ -9,7 +9,6 @@ const ActionTab: FunctionComponent<
TabComponentProps<unknown, Action<string>> TabComponentProps<unknown, Action<string>>
> = ({ > = ({
action, action,
styling,
base16Theme, base16Theme,
invertTheme, invertTheme,
labelRenderer, labelRenderer,
@ -21,7 +20,7 @@ const ActionTab: FunctionComponent<
theme={getJsonTreeTheme(base16Theme)} theme={getJsonTreeTheme(base16Theme)}
data={action} data={action}
getItemString={(type, data) => getItemString={(type, data) =>
getItemString(styling, type, data, dataTypeKey, isWideLayout) getItemString(type, data, dataTypeKey, isWideLayout)
} }
invertTheme={invertTheme} invertTheme={invertTheme}
hideRoot hideRoot

View File

@ -7,7 +7,6 @@ const DiffTab: FunctionComponent<
TabComponentProps<unknown, Action<string>> TabComponentProps<unknown, Action<string>>
> = ({ > = ({
delta, delta,
styling,
base16Theme, base16Theme,
invertTheme, invertTheme,
labelRenderer, labelRenderer,
@ -17,7 +16,6 @@ const DiffTab: FunctionComponent<
<JSONDiff <JSONDiff
{...{ {...{
delta, delta,
styling,
base16Theme, base16Theme,
invertTheme, invertTheme,
labelRenderer, labelRenderer,

View File

@ -3,8 +3,9 @@ import { JSONTree } from 'react-json-tree';
import type { LabelRenderer, ShouldExpandNodeInitially } from 'react-json-tree'; import type { LabelRenderer, ShouldExpandNodeInitially } from 'react-json-tree';
import { stringify } from 'javascript-stringify'; import { stringify } from 'javascript-stringify';
import { Delta } from 'jsondiffpatch'; import { Delta } from 'jsondiffpatch';
import { StylingFunction } from 'react-base16-styling';
import { Base16Theme } from 'redux-devtools-themes'; import { Base16Theme } from 'redux-devtools-themes';
import { css } from '@emotion/react';
import type { Interpolation, Theme } from '@emotion/react';
import getItemString from './getItemString'; import getItemString from './getItemString';
import getJsonTreeTheme from './getJsonTreeTheme'; import getJsonTreeTheme from './getJsonTreeTheme';
@ -46,9 +47,18 @@ function prepareDelta(value: any) {
return value; return value;
} }
const diffCss: Interpolation<Theme> = (theme) => ({
padding: '2px 3px',
borderRadius: '3px',
position: 'relative',
color: theme.TEXT_COLOR,
});
const diffWrapCss = css({ position: 'relative', zIndex: 1 });
interface Props { interface Props {
delta: Delta | null | undefined | false; delta: Delta | null | undefined | false;
styling: StylingFunction;
base16Theme: Base16Theme; base16Theme: Base16Theme;
invertTheme: boolean; invertTheme: boolean;
labelRenderer: LabelRenderer; labelRenderer: LabelRenderer;
@ -82,10 +92,19 @@ export default class JSONDiff extends Component<Props, State> {
} }
render() { render() {
const { styling, base16Theme, ...props } = this.props; const { base16Theme, ...props } = this.props;
if (!this.state.data) { if (!this.state.data) {
return <div {...styling('stateDiffEmpty')}>(states are equal)</div>; return (
<div
css={(theme) => ({
padding: '10px',
color: theme.TEXT_PLACEHOLDER_COLOR,
})}
>
(states are equal)
</div>
);
} }
return ( return (
@ -105,7 +124,6 @@ export default class JSONDiff extends Component<Props, State> {
getItemString = (type: string, data: any) => getItemString = (type: string, data: any) =>
getItemString( getItemString(
this.props.styling,
type, type,
data, data,
this.props.dataTypeKey, this.props.dataTypeKey,
@ -114,45 +132,71 @@ export default class JSONDiff extends Component<Props, State> {
); );
valueRenderer = (raw: any, value: any) => { valueRenderer = (raw: any, value: any) => {
const { styling, isWideLayout } = this.props; const { isWideLayout } = this.props;
function renderSpan(name: string, body: string) {
return (
<span key={name} {...styling(['diff', name])}>
{body}
</span>
);
}
if (Array.isArray(value)) { if (Array.isArray(value)) {
switch (value.length) { switch (value.length) {
case 1: case 1:
return ( return (
<span {...styling('diffWrap')}> <span css={diffWrapCss}>
{renderSpan( <span
'diffAdd', key="diffAdd"
stringifyAndShrink(value[0], isWideLayout), css={[
)} diffCss,
(theme) => ({ backgroundColor: theme.DIFF_ADD_COLOR }),
]}
>
{stringifyAndShrink(value[0], isWideLayout)}
</span>
</span> </span>
); );
case 2: case 2:
return ( return (
<span {...styling('diffWrap')}> <span css={diffWrapCss}>
{renderSpan( <span
'diffUpdateFrom', key="diffUpdateFrom"
stringifyAndShrink(value[0], isWideLayout), css={[
)} diffCss,
{renderSpan('diffUpdateArrow', ' => ')} (theme) => ({
{renderSpan( textDecoration: 'line-through',
'diffUpdateTo', backgroundColor: theme.DIFF_REMOVE_COLOR,
stringifyAndShrink(value[1], isWideLayout), }),
)} ]}
>
{stringifyAndShrink(value[0], isWideLayout)}
</span>
<span
key="diffUpdateArrow"
css={[diffCss, (theme) => ({ color: theme.DIFF_ARROW_COLOR })]}
>
{' => '}
</span>
<span
key="diffUpdateTo"
css={[
diffCss,
(theme) => ({ backgroundColor: theme.DIFF_ADD_COLOR }),
]}
>
{stringifyAndShrink(value[1], isWideLayout)}
</span>
</span> </span>
); );
case 3: case 3:
return ( return (
<span {...styling('diffWrap')}> <span css={diffWrapCss}>
{renderSpan('diffRemove', stringifyAndShrink(value[0]))} <span
key="diffRemove"
css={[
diffCss,
(theme) => ({
textDecoration: 'line-through',
backgroundColor: theme.DIFF_REMOVE_COLOR,
}),
]}
>
{stringifyAndShrink(value[0])}
</span>
</span> </span>
); );
} }

View File

@ -9,7 +9,6 @@ const StateTab: React.FunctionComponent<
TabComponentProps<any, Action<string>> TabComponentProps<any, Action<string>>
> = ({ > = ({
nextState, nextState,
styling,
base16Theme, base16Theme,
invertTheme, invertTheme,
labelRenderer, labelRenderer,
@ -23,7 +22,7 @@ const StateTab: React.FunctionComponent<
theme={getJsonTreeTheme(base16Theme)} theme={getJsonTreeTheme(base16Theme)}
data={nextState} data={nextState}
getItemString={(type, data) => getItemString={(type, data) =>
getItemString(styling, type, data, dataTypeKey, isWideLayout) getItemString(type, data, dataTypeKey, isWideLayout)
} }
invertTheme={invertTheme} invertTheme={invertTheme}
hideRoot hideRoot

View File

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import { isCollection, isIndexed, isKeyed } from 'immutable'; import { isCollection, isIndexed, isKeyed } from 'immutable';
import { StylingFunction } from 'react-base16-styling';
import isIterable from '../utils/isIterable'; import isIterable from '../utils/isIterable';
const IS_IMMUTABLE_KEY = '@@__IS_IMMUTABLE__@@'; const IS_IMMUTABLE_KEY = '@@__IS_IMMUTABLE__@@';
@ -72,14 +71,13 @@ function getText(
} }
const getItemString = ( const getItemString = (
styling: StylingFunction,
type: string, type: string,
data: any, data: any,
dataTypeKey: string | symbol | undefined, dataTypeKey: string | symbol | undefined,
isWideLayout: boolean, isWideLayout: boolean,
isDiff?: boolean, isDiff?: boolean,
) => ( ) => (
<span {...styling('treeItemHint')}> <span css={(theme) => ({ color: theme.ITEM_HINT_COLOR })}>
{data[IS_IMMUTABLE_KEY] ? 'Immutable' : ''} {data[IS_IMMUTABLE_KEY] ? 'Immutable' : ''}
{dataTypeKey && data[dataTypeKey] ? `${data[dataTypeKey] as string} ` : ''} {dataTypeKey && data[dataTypeKey] ? `${data[dataTypeKey] as string} ` : ''}
{getText(type, data, isWideLayout, isDiff)} {getText(type, data, isWideLayout, isDiff)}

View File

@ -1,394 +0,0 @@
import jss, { StyleSheet } from 'jss';
import preset from 'jss-preset-default';
import { createStyling, StylingFunction, Theme } from 'react-base16-styling';
import rgba from 'hex-rgba';
import { Base16Theme } from 'redux-devtools-themes';
import type { CurriedFunction1 } from 'lodash';
import inspector from '../themes/inspector';
import * as reduxThemes from 'redux-devtools-themes';
import * as inspectorThemes from '../themes';
jss.setup(preset());
const colorMap = (theme: Base16Theme) => ({
TEXT_COLOR: theme.base06,
TEXT_PLACEHOLDER_COLOR: rgba(theme.base06, 60),
BACKGROUND_COLOR: theme.base00,
SELECTED_BACKGROUND_COLOR: rgba(theme.base03, 20),
SKIPPED_BACKGROUND_COLOR: rgba(theme.base03, 10),
HEADER_BACKGROUND_COLOR: rgba(theme.base03, 30),
HEADER_BORDER_COLOR: rgba(theme.base03, 20),
BORDER_COLOR: rgba(theme.base03, 50),
LIST_BORDER_COLOR: rgba(theme.base03, 50),
ACTION_TIME_BACK_COLOR: rgba(theme.base03, 20),
ACTION_TIME_COLOR: theme.base04,
PIN_COLOR: theme.base04,
ITEM_HINT_COLOR: rgba(theme.base0F, 90),
TAB_BACK_SELECTED_COLOR: rgba(theme.base03, 20),
TAB_BACK_COLOR: rgba(theme.base00, 70),
TAB_BACK_HOVER_COLOR: rgba(theme.base03, 40),
TAB_BORDER_COLOR: rgba(theme.base03, 50),
DIFF_ADD_COLOR: rgba(theme.base0B, 40),
DIFF_REMOVE_COLOR: rgba(theme.base08, 40),
DIFF_ARROW_COLOR: theme.base0E,
LINK_COLOR: rgba(theme.base0E, 90),
LINK_HOVER_COLOR: theme.base0E,
ERROR_COLOR: theme.base08,
});
type Color = keyof ReturnType<typeof colorMap>;
type ColorMap = {
[color in Color]: string;
};
const getSheetFromColorMap = (map: ColorMap) => ({
inspector: {
display: 'flex',
'flex-direction': 'column',
width: '100%',
height: '100%',
'font-family': 'monaco, Consolas, "Lucida Console", monospace',
'font-size': '12px',
'font-smoothing': 'antialiased',
'line-height': '1.5em',
'background-color': map.BACKGROUND_COLOR,
color: map.TEXT_COLOR,
},
inspectorWide: {
'flex-direction': 'row',
},
actionList: {
'flex-basis': '40%',
'flex-shrink': 0,
'overflow-x': 'hidden',
'overflow-y': 'auto',
'border-bottom-width': '3px',
'border-bottom-style': 'double',
display: 'flex',
'flex-direction': 'column',
'background-color': map.BACKGROUND_COLOR,
'border-color': map.LIST_BORDER_COLOR,
},
actionListHeader: {
display: 'flex',
flex: '0 0 auto',
'align-items': 'center',
'border-bottom-width': '1px',
'border-bottom-style': 'solid',
'border-color': map.LIST_BORDER_COLOR,
},
actionListRows: {
overflow: 'auto',
},
actionListHeaderSelector: {
display: 'inline-flex',
'margin-right': '10px',
},
actionListWide: {
'flex-basis': '40%',
'border-bottom': 'none',
'border-right-width': '3px',
'border-right-style': 'double',
},
actionListItem: {
'border-bottom-width': '1px',
'border-bottom-style': 'solid',
display: 'flex',
'justify-content': 'space-between',
padding: '5px 10px',
cursor: 'pointer',
'user-select': 'none',
'border-bottom-color': map.BORDER_COLOR,
},
actionListItemSelected: {
'background-color': map.SELECTED_BACKGROUND_COLOR,
},
actionListItemSkipped: {
'background-color': map.SKIPPED_BACKGROUND_COLOR,
},
actionListFromFuture: {
opacity: '0.6',
},
actionListItemButtons: {
position: 'relative',
height: '20px',
display: 'flex',
},
actionListItemTime: {
display: 'inline',
padding: '4px 6px',
'border-radius': '3px',
'font-size': '0.8em',
'line-height': '1em',
'flex-shrink': 0,
'background-color': map.ACTION_TIME_BACK_COLOR,
color: map.ACTION_TIME_COLOR,
},
actionListItemSelector: {
display: 'inline-flex',
},
actionListItemName: {
overflow: 'hidden',
'text-overflow': 'ellipsis',
'line-height': '20px',
},
actionListItemNameSkipped: {
'text-decoration': 'line-through',
opacity: 0.3,
},
actionListHeaderSearch: {
outline: 'none',
border: 'none',
width: '100%',
padding: '5px 10px',
'font-size': '1em',
'font-family': 'monaco, Consolas, "Lucida Console", monospace',
'background-color': map.BACKGROUND_COLOR,
color: map.TEXT_COLOR,
'&::-webkit-input-placeholder': {
color: map.TEXT_PLACEHOLDER_COLOR,
},
'&::-moz-placeholder': {
color: map.TEXT_PLACEHOLDER_COLOR,
},
},
actionListHeaderWrapper: {
position: 'relative',
height: '20px',
},
actionPreview: {
flex: 1,
display: 'flex',
'flex-direction': 'column',
'flex-grow': 1,
'overflow-y': 'hidden',
'& pre': {
border: 'inherit',
'border-radius': '3px',
'line-height': 'inherit',
color: 'inherit',
},
'background-color': map.BACKGROUND_COLOR,
},
actionPreviewContent: {
flex: 1,
'overflow-y': 'auto',
},
stateDiff: {
padding: '5px 0',
},
stateDiffEmpty: {
padding: '10px',
color: map.TEXT_PLACEHOLDER_COLOR,
},
stateError: {
padding: '10px',
'margin-left': '14px',
'font-weight': 'bold',
color: map.ERROR_COLOR,
},
inspectedPath: {
padding: '6px 0',
},
inspectedPathKey: {
'&:not(:last-child):after': {
content: '" > "',
},
},
inspectedPathKeyLink: {
cursor: 'pointer',
color: map.LINK_COLOR,
'&:hover': {
'text-decoration': 'underline',
color: map.LINK_HOVER_COLOR,
},
},
treeItemPin: {
'font-size': '0.7em',
'padding-left': '5px',
cursor: 'pointer',
'&:hover': {
'text-decoration': 'underline',
},
color: map.PIN_COLOR,
},
treeItemHint: {
color: map.ITEM_HINT_COLOR,
},
previewHeader: {
flex: '0 0 30px',
padding: '5px 10px',
'align-items': 'center',
'border-bottom-width': '1px',
'border-bottom-style': 'solid',
'background-color': map.HEADER_BACKGROUND_COLOR,
'border-bottom-color': map.HEADER_BORDER_COLOR,
},
tabSelector: {
position: 'relative',
display: 'inline-flex',
float: 'right',
},
selectorButton: {
cursor: 'pointer',
position: 'relative',
padding: '5px 10px',
'border-style': 'solid',
'border-width': '1px',
'border-left-width': 0,
'&:first-child': {
'border-left-width': '1px',
'border-top-left-radius': '3px',
'border-bottom-left-radius': '3px',
},
'&:last-child': {
'border-top-right-radius': '3px',
'border-bottom-right-radius': '3px',
},
'background-color': map.TAB_BACK_COLOR,
'&:hover': {
'background-color': map.TAB_BACK_HOVER_COLOR,
},
'border-color': map.TAB_BORDER_COLOR,
},
selectorButtonSmall: {
padding: '0px 8px',
'font-size': '0.8em',
},
selectorButtonSelected: {
'background-color': map.TAB_BACK_SELECTED_COLOR,
},
diff: {
padding: '2px 3px',
'border-radius': '3px',
position: 'relative',
color: map.TEXT_COLOR,
},
diffWrap: {
position: 'relative',
'z-index': 1,
},
diffAdd: {
'background-color': map.DIFF_ADD_COLOR,
},
diffRemove: {
'text-decoration': 'line-through',
'background-color': map.DIFF_REMOVE_COLOR,
},
diffUpdateFrom: {
'text-decoration': 'line-through',
'background-color': map.DIFF_REMOVE_COLOR,
},
diffUpdateTo: {
'background-color': map.DIFF_ADD_COLOR,
},
diffUpdateArrow: {
color: map.DIFF_ARROW_COLOR,
},
rightSlider: {
'font-smoothing': 'subpixel-antialiased', // http://stackoverflow.com/a/21136111/4218591
position: 'absolute',
right: 0,
transform: 'translateX(150%)',
transition: 'transform 0.2s ease-in-out',
},
rightSliderRotate: {
transform: 'rotateX(90deg)',
transition: 'transform 0.2s ease-in-out 0.08s',
},
rightSliderShown: {
position: 'static',
transform: 'translateX(0)',
},
rightSliderRotateShown: {
transform: 'rotateX(0)',
transition: 'transform 0.2s ease-in-out 0.18s',
},
});
let themeSheet: StyleSheet;
const getDefaultThemeStyling = (theme: Base16Theme) => {
if (themeSheet) {
themeSheet.detach();
}
themeSheet = jss
.createStyleSheet(getSheetFromColorMap(colorMap(theme)))
.attach();
return themeSheet.classes;
};
export const base16Themes = { ...reduxThemes, ...inspectorThemes };
export const createStylingFromTheme: CurriedFunction1<
Theme | undefined,
StylingFunction
> = createStyling(getDefaultThemeStyling, {
defaultBase16: inspector,
base16Themes,
});

View File

@ -0,0 +1,39 @@
import { css } from '@emotion/react';
import type { Interpolation, Theme } from '@emotion/react';
export const selectorButtonCss: Interpolation<Theme> = (theme) => ({
cursor: 'pointer',
position: 'relative',
padding: '5px 10px',
borderStyle: 'solid',
borderWidth: '1px',
borderLeftWidth: 0,
'&:first-of-type': {
borderLeftWidth: '1px',
borderTopLeftRadius: '3px',
borderBottomLeftRadius: '3px',
},
'&:last-of-type': {
borderTopRightRadius: '3px',
borderBottomRightRadius: '3px',
},
backgroundColor: theme.TAB_BACK_COLOR,
'&:hover': {
backgroundColor: theme.TAB_BACK_HOVER_COLOR,
},
borderColor: theme.TAB_BORDER_COLOR,
});
export const selectorButtonSmallCss = css({
padding: '0px 8px',
fontSize: '0.8em',
});
export const selectorButtonSelectedCss: Interpolation<Theme> = (theme) => ({
backgroundColor: theme.TAB_BACK_SELECTED_COLOR,
});

View File

@ -0,0 +1,76 @@
import rgba from 'hex-rgba';
import { Base16Theme } from 'redux-devtools-themes';
import * as reduxThemes from 'redux-devtools-themes';
import * as inspectorThemes from '../themes';
import { getBase16Theme, invertBase16Theme } from 'react-base16-styling';
const base16Themes = { ...reduxThemes, ...inspectorThemes };
export type Base16ThemeName = keyof typeof base16Themes;
export function resolveBase16Theme(theme: Base16ThemeName | Base16Theme) {
return getBase16Theme(theme, base16Themes);
}
declare module '@emotion/react' {
export interface Theme {
TEXT_COLOR: string;
TEXT_PLACEHOLDER_COLOR: string;
BACKGROUND_COLOR: string;
SELECTED_BACKGROUND_COLOR: string;
SKIPPED_BACKGROUND_COLOR: string;
HEADER_BACKGROUND_COLOR: string;
HEADER_BORDER_COLOR: string;
BORDER_COLOR: string;
LIST_BORDER_COLOR: string;
ACTION_TIME_BACK_COLOR: string;
ACTION_TIME_COLOR: string;
PIN_COLOR: string;
ITEM_HINT_COLOR: string;
TAB_BACK_SELECTED_COLOR: string;
TAB_BACK_COLOR: string;
TAB_BACK_HOVER_COLOR: string;
TAB_BORDER_COLOR: string;
DIFF_ADD_COLOR: string;
DIFF_REMOVE_COLOR: string;
DIFF_ARROW_COLOR: string;
LINK_COLOR: string;
LINK_HOVER_COLOR: string;
ERROR_COLOR: string;
}
}
const colorMap = (theme: Base16Theme) => ({
TEXT_COLOR: theme.base06,
TEXT_PLACEHOLDER_COLOR: rgba(theme.base06, 60),
BACKGROUND_COLOR: theme.base00,
SELECTED_BACKGROUND_COLOR: rgba(theme.base03, 20),
SKIPPED_BACKGROUND_COLOR: rgba(theme.base03, 10),
HEADER_BACKGROUND_COLOR: rgba(theme.base03, 30),
HEADER_BORDER_COLOR: rgba(theme.base03, 20),
BORDER_COLOR: rgba(theme.base03, 50),
LIST_BORDER_COLOR: rgba(theme.base03, 50),
ACTION_TIME_BACK_COLOR: rgba(theme.base03, 20),
ACTION_TIME_COLOR: theme.base04,
PIN_COLOR: theme.base04,
ITEM_HINT_COLOR: rgba(theme.base0F, 90),
TAB_BACK_SELECTED_COLOR: rgba(theme.base03, 20),
TAB_BACK_COLOR: rgba(theme.base00, 70),
TAB_BACK_HOVER_COLOR: rgba(theme.base03, 40),
TAB_BORDER_COLOR: rgba(theme.base03, 50),
DIFF_ADD_COLOR: rgba(theme.base0B, 40),
DIFF_REMOVE_COLOR: rgba(theme.base08, 40),
DIFF_ARROW_COLOR: theme.base0E,
LINK_COLOR: rgba(theme.base0E, 90),
LINK_HOVER_COLOR: theme.base0E,
ERROR_COLOR: theme.base08,
});
export function createInspectorMonitorThemeFromBase16Theme(
base16Theme: Base16Theme,
invertTheme: boolean,
) {
const finalBase16Theme = invertTheme
? invertBase16Theme(base16Theme)
: base16Theme;
return colorMap(finalBase16Theme);
}

View File

@ -2,7 +2,9 @@
"extends": "../../tsconfig.react.base.json", "extends": "../../tsconfig.react.base.json",
"compilerOptions": { "compilerOptions": {
"outDir": "lib/types", "outDir": "lib/types",
"resolveJsonModule": true "resolveJsonModule": true,
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react"
}, },
"include": ["src"] "include": ["src"]
} }

View File

@ -59,6 +59,9 @@ importers:
'@babel/polyfill': '@babel/polyfill':
specifier: ^7.12.1 specifier: ^7.12.1
version: 7.12.1 version: 7.12.1
'@emotion/react':
specifier: ^11.11.1
version: 11.11.1(@types/react@18.2.43)(react@18.2.0)
'@redux-devtools/app': '@redux-devtools/app':
specifier: ^4.0.1 specifier: ^4.0.1
version: link:../packages/redux-devtools-app version: link:../packages/redux-devtools-app
@ -1088,6 +1091,9 @@ importers:
'@babel/preset-typescript': '@babel/preset-typescript':
specifier: ^7.23.3 specifier: ^7.23.3
version: 7.23.3(@babel/core@7.23.5) version: 7.23.3(@babel/core@7.23.5)
'@emotion/react':
specifier: ^11.11.1
version: 11.11.1(@types/react@18.2.43)(react@18.2.0)
'@rjsf/core': '@rjsf/core':
specifier: ^4.2.3 specifier: ^4.2.3
version: 4.2.3(react@18.2.0) version: 4.2.3(react@18.2.0)
@ -1293,6 +1299,9 @@ importers:
'@apollo/server': '@apollo/server':
specifier: ^4.9.5 specifier: ^4.9.5
version: 4.9.5(graphql@16.8.1) version: 4.9.5(graphql@16.8.1)
'@emotion/react':
specifier: ^11.11.1
version: 11.11.1(@types/react@18.2.43)(react@18.2.0)
'@redux-devtools/app': '@redux-devtools/app':
specifier: ^4.0.0 specifier: ^4.0.0
version: link:../redux-devtools-app version: link:../redux-devtools-app
@ -1605,12 +1614,6 @@ importers:
jsondiffpatch: jsondiffpatch:
specifier: ^0.5.0 specifier: ^0.5.0
version: 0.5.0 version: 0.5.0
jss:
specifier: ^10.10.0
version: 10.10.0
jss-preset-default:
specifier: ^10.10.0
version: 10.10.0
lodash.debounce: lodash.debounce:
specifier: ^4.0.8 specifier: ^4.0.8
version: 4.0.8 version: 4.0.8
@ -1648,6 +1651,12 @@ importers:
'@babel/preset-typescript': '@babel/preset-typescript':
specifier: ^7.23.3 specifier: ^7.23.3
version: 7.23.3(@babel/core@7.23.5) version: 7.23.3(@babel/core@7.23.5)
'@emotion/babel-preset-css-prop':
specifier: ^11.11.0
version: 11.11.0(@babel/core@7.23.5)
'@emotion/react':
specifier: ^11.11.1
version: 11.11.1(@types/react@18.2.43)(react@18.2.0)
'@redux-devtools/core': '@redux-devtools/core':
specifier: ^3.14.0 specifier: ^3.14.0
version: link:../redux-devtools version: link:../redux-devtools
@ -1751,6 +1760,9 @@ importers:
'@babel/preset-typescript': '@babel/preset-typescript':
specifier: ^7.23.3 specifier: ^7.23.3
version: 7.23.3(@babel/core@7.23.5) version: 7.23.3(@babel/core@7.23.5)
'@emotion/react':
specifier: ^11.11.1
version: 11.11.1(@types/react@18.2.43)(react@18.2.0)
'@redux-devtools/core': '@redux-devtools/core':
specifier: ^3.14.0 specifier: ^3.14.0
version: link:../redux-devtools version: link:../redux-devtools
@ -1823,6 +1835,9 @@ importers:
packages/redux-devtools-inspector-monitor-test-tab/demo: packages/redux-devtools-inspector-monitor-test-tab/demo:
dependencies: dependencies:
'@emotion/react':
specifier: ^11.11.1
version: 11.11.1(@types/react@18.2.43)(react@18.2.0)
'@redux-devtools/core': '@redux-devtools/core':
specifier: ^3.13.2 specifier: ^3.13.2
version: link:../../redux-devtools version: link:../../redux-devtools
@ -2002,6 +2017,9 @@ importers:
'@babel/preset-typescript': '@babel/preset-typescript':
specifier: ^7.23.3 specifier: ^7.23.3
version: 7.23.3(@babel/core@7.23.5) version: 7.23.3(@babel/core@7.23.5)
'@emotion/react':
specifier: ^11.11.1
version: 11.11.1(@types/react@18.2.43)(react@18.2.0)
'@redux-devtools/core': '@redux-devtools/core':
specifier: ^3.14.0 specifier: ^3.14.0
version: link:../redux-devtools version: link:../redux-devtools
@ -2086,6 +2104,9 @@ importers:
packages/redux-devtools-inspector-monitor/demo: packages/redux-devtools-inspector-monitor/demo:
dependencies: dependencies:
'@emotion/react':
specifier: ^11.11.1
version: 11.11.1(@types/react@18.2.43)(react@18.2.0)
'@redux-devtools/core': '@redux-devtools/core':
specifier: ^3.13.0 specifier: ^3.13.0
version: link:../../redux-devtools version: link:../../redux-devtools
@ -6429,6 +6450,15 @@ packages:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
/@emotion/babel-plugin-jsx-pragmatic@0.2.1(@babel/core@7.23.5):
resolution: {integrity: sha512-xy1SlgEJygAAIvIuC2idkGKJYa6v5iwoyILkvNKgk347bV+IImXrUat5Z86EmLGyWhEoTplVT9EHqTnHZG4HFw==}
peerDependencies:
'@babel/core': ^7.0.0
dependencies:
'@babel/core': 7.23.5
'@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.5)
dev: true
/@emotion/babel-plugin@11.11.0: /@emotion/babel-plugin@11.11.0:
resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==}
dependencies: dependencies:
@ -6443,7 +6473,18 @@ packages:
find-root: 1.1.0 find-root: 1.1.0
source-map: 0.5.7 source-map: 0.5.7
stylis: 4.2.0 stylis: 4.2.0
dev: false
/@emotion/babel-preset-css-prop@11.11.0(@babel/core@7.23.5):
resolution: {integrity: sha512-+1Cba68IyBeltWzvbBSXcBWqP2eKQuQcSUpIu3ma4pOUeRol4EvwWrYS2Rv51aIVqg066fLB+Z9O/8NKR7uUlQ==}
peerDependencies:
'@babel/core': ^7.0.0
dependencies:
'@babel/core': 7.23.5
'@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.23.5)
'@babel/runtime': 7.23.5
'@emotion/babel-plugin': 11.11.0
'@emotion/babel-plugin-jsx-pragmatic': 0.2.1(@babel/core@7.23.5)
dev: true
/@emotion/cache@11.11.0: /@emotion/cache@11.11.0:
resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==} resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==}
@ -6453,11 +6494,9 @@ packages:
'@emotion/utils': 1.2.1 '@emotion/utils': 1.2.1
'@emotion/weak-memoize': 0.3.1 '@emotion/weak-memoize': 0.3.1
stylis: 4.2.0 stylis: 4.2.0
dev: false
/@emotion/hash@0.9.1: /@emotion/hash@0.9.1:
resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==}
dev: false
/@emotion/is-prop-valid@0.8.8: /@emotion/is-prop-valid@0.8.8:
resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==}
@ -6500,7 +6539,6 @@ packages:
'@types/react': 18.2.43 '@types/react': 18.2.43
hoist-non-react-statics: 3.3.2 hoist-non-react-statics: 3.3.2
react: 18.2.0 react: 18.2.0
dev: false
/@emotion/serialize@1.1.2: /@emotion/serialize@1.1.2:
resolution: {integrity: sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==} resolution: {integrity: sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==}
@ -6510,11 +6548,9 @@ packages:
'@emotion/unitless': 0.8.1 '@emotion/unitless': 0.8.1
'@emotion/utils': 1.2.1 '@emotion/utils': 1.2.1
csstype: 3.1.2 csstype: 3.1.2
dev: false
/@emotion/sheet@1.2.2: /@emotion/sheet@1.2.2:
resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==} resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==}
dev: false
/@emotion/styled@11.11.0(@emotion/react@11.11.1)(@types/react@18.2.43)(react@18.2.0): /@emotion/styled@11.11.0(@emotion/react@11.11.1)(@types/react@18.2.43)(react@18.2.0):
resolution: {integrity: sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==} resolution: {integrity: sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==}
@ -6545,7 +6581,6 @@ packages:
/@emotion/unitless@0.8.1: /@emotion/unitless@0.8.1:
resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==}
dev: false
/@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0): /@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0):
resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==} resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==}
@ -6556,11 +6591,9 @@ packages:
/@emotion/utils@1.2.1: /@emotion/utils@1.2.1:
resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==} resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==}
dev: false
/@emotion/weak-memoize@0.3.1: /@emotion/weak-memoize@0.3.1:
resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==} resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==}
dev: false
/@esbuild/android-arm64@0.18.20: /@esbuild/android-arm64@0.18.20:
resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
@ -11565,7 +11598,6 @@ packages:
'@babel/runtime': 7.23.5 '@babel/runtime': 7.23.5
cosmiconfig: 7.1.0 cosmiconfig: 7.1.0
resolve: 1.22.8 resolve: 1.22.8
dev: false
/babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.23.5): /babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.23.5):
resolution: {integrity: sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==} resolution: {integrity: sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==}
@ -12371,7 +12403,6 @@ packages:
/convert-source-map@1.9.0: /convert-source-map@1.9.0:
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
dev: false
/convert-source-map@2.0.0: /convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
@ -14279,7 +14310,6 @@ packages:
/find-root@1.1.0: /find-root@1.1.0:
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
dev: false
/find-up@3.0.0: /find-up@3.0.0:
resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==}
@ -19835,7 +19865,6 @@ packages:
/source-map@0.5.7: /source-map@0.5.7:
resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dev: false
/source-map@0.6.1: /source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
@ -20280,7 +20309,6 @@ packages:
/stylis@4.2.0: /stylis@4.2.0:
resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
dev: false
/sumchecker@3.0.1: /sumchecker@3.0.1:
resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}