redux-devtools/packages/redux-devtools-rtk-query-monitor/src/styles/createStylingFromTheme.ts
Fabrizio Vitale 7d92a5e186
[feat][monitor] Add rkt-query-inspector-monitor - feat/rtk query monitor (#750)
* chore: copy rtk-query example from toolkit

* feat(rtk-query): complete initial setup of rtk-query

* feat: complete inspector layout and add initial JSONTree setup

* fix: unintentional removal of tsconfig

* feat(search): add search logic and refactor monitor state shape

* fix: inverted monitor theme inside  devtoop-app

Othetr changes:

* simplify monitor integration

* fix: rtk monitor reducer not working in  app

* refactor(rtk-query): simplify theme config

* feat(rtk-query-monitor): add query preview tabs

* fix: wip

* refactor(examples): add rtk-query-polling to workspace

Other changes:

* docs(rtk-query-polling): add README.md

* chore(rtk-query-inspector): add demo to monorepo

Other changes:

chore: increase isWideScreen polling interval to 300

refactor: add subscription as root node in QueryPreviewSubscriptions

* feat(rtk-query): add multiple filter options

* chore(rtk-queery): rename demo build script and add SKIP_PREFLIGHT_CHECK=true

* feat(rtk-query): display status flags in QueryPreviewInfo

* chore(rtk-query): update typescript versions in rkt-inspector-monitor & its demo

* docs(rtk-query): add proper README

Other changes:

* fix examples/rtk-query-poilling

* docs(rtk-query): improve rtk-query-inspector-monitor demo gif

* docs(rtk-query): clean up demo

* fix(rtk-query): clear button not updating redux state

* docs(rtk-query): add link to rtk-query-inspector-monitor demo site

* chore(rtk-query): run prettier after prettier upgrade (55e2284)

* docs(rtk.query): clean up readme add features, todo and development section

* docs(rtk-query): fix link href

* chore(rtk-query): clean up rtk-query-imspector-monitor-demo and add post example

* feat(rtk-query): add counters on tags & subs tab buttons

* fix(rtk-query): layering issue between queryPreview tabList and select

Other changes:

* clean up demo styles

* run prettier

* fix: revert accidental changes packages/redux-devtools-serialize/tsconfig.json

* chore: change QueryComparators.fulfilledTimeStamp label

* feat(rtk-query): display api stats

* refactor: remove rtk-query-polling example from monorepo

* chore: regenerate lock file and add @types/react as monorepo devDep

* chore: display apiState

Other changes:

* fix close button overflow

* minor responsive style tweaks

* display reducerPath in query tab

* fix(rtk-query): resolve CI errors

- fix(prettier:check): unformatted file
- fix(lint:all): fix accidentallly removed .eslintignore

* chore(rtk-query): rename package to '@redux-devtools/rtk-query-monitor'

* fix(rtk-query): lint:all error

https://github.com/reduxjs/redux-devtools/runs/2869729048?check_suite_focus=true

* feat(rtk-query): add fallback message if there are no rtk-query apis

* refactor(rtk-query): move Inspector & Monitor to containers clean up typings

Other changes:

* chore: improved type coverage

* chore: do not lint packages/redux-devtools-rtk-query-monitor/demo folder

* refactor: put sort order buttons inside a component

* chore: hopefully resolve mockServiceWorker formatting issues

* fix(rtk-query): incorrect link color

Other changes:

* fix: add missing anchor property value noopener

* refactor(rtk-query): simplify sort order control

* feat(rtk-query): add timings to apiStats sections

* feat(rtk-query): add slowest and fastest in timings section

* feat(rtk-query): improve formatting of timings and display average loading time

* fix(rtk-query): rtk-query imports

* refactor(rtk-query): reduce selector computations

Other changes:

* simplify TreeView props

* feat(rtk-query): add actions tab

* refactor(rtk-query): add custom logic for TreeView shouldExpandNode

Other changes:

* feat: added duration in QueryPreviewInfo tab

* refactor: TreeView component

* chore(rtk-query): improve demo visibility on small devices

* feat(rtk-query): do not display tree node preview

Other changes:

* improve visibility of demo devTools on small devices

* tweak QueryPreviewInfo labels

* chore(rtk-query): improve responsiveness

* refactor(rtk-query): move preview to containers remove unnecessary computation

* feat(rtk-query): display median of timings

Other changes:

* improved shouldExpandNode logic of QueryPreviewActions

* tweaked mean logic

* refactor(rtk-query-monitor): conform demo setup to repo standards

* chore(rtk-query-monitor): add option to select active devtools

* chore(rtk-query-monitor): remove redux-devtools/examples/rtk-query-polling

* refactor(rtk-query): improve UI of api tab

* feat(rtk-query): add regex search

* feat(rtk-query): display mutations in queryList

* refactor(rtk-query): track all fulfilled requests using actions

Other changes:

* refactor(rtk-query): rename tally properties

* chore(rtk-query): update @redux-devtools/rtk-query-monitor dependencies

* fix(rtk-query): demo build failing caused by a typing error
2021-08-26 15:33:06 -04:00

560 lines
13 KiB
TypeScript

import jss, { StyleSheet } from 'jss';
import preset from 'jss-preset-default';
import {
createStyling,
getBase16Theme,
invertTheme,
StylingConfig,
} from 'react-base16-styling';
import rgba from 'hex-rgba';
import * as reduxThemes from 'redux-devtools-themes';
import { Action } from 'redux';
import { RtkQueryMonitorProps, StyleUtils } from '../types';
import { createContext } from 'react';
jss.setup(preset());
export const colorMap = (theme: reduxThemes.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,
ULIST_DISC_COLOR: theme.base0D,
ULIST_COLOR: rgba(theme.base06, 60),
ULIST_STRONG_COLOR: theme.base0B,
TAB_CONTENT_COLOR: rgba(theme.base06, 60),
TOGGLE_BUTTON_BACKGROUND: rgba(theme.base00, 70),
TOGGLE_BUTTON_SELECTED_BACKGROUND: theme.base04,
TOGGLE_BUTTON_ERROR: rgba(theme.base08, 40),
} as const);
type Color = keyof ReturnType<typeof colorMap>;
type ColorMap = {
[color in Color]: string;
};
const getSheetFromColorMap = (map: ColorMap) => {
const appearanceNone = {
'-webkit-appearance': 'none',
};
return {
inspector: {
display: 'flex',
flexFlow: 'column nowrap',
overflow: 'hidden',
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,
'&[data-wide-layout="1"]': {
flexFlow: 'row nowrap',
},
},
querySectionWrapper: {
display: 'flex',
flex: '0 0 auto',
height: '50%',
width: '100%',
borderColor: map.TAB_BORDER_COLOR,
'&[data-wide-layout="0"]': {
borderBottomWidth: 1,
borderStyle: 'solid',
},
'&[data-wide-layout="1"]': {
height: '100%',
width: '44%',
borderRightWidth: 1,
borderStyle: 'solid',
},
flexFlow: 'column nowrap',
'& > :first-child': {
flex: '0 0 auto',
'border-bottom-width': '1px',
'border-bottom-style': 'solid',
'border-color': map.LIST_BORDER_COLOR,
},
'& > :nth-child(n + 2)': {
flex: '1 1 auto',
overflowX: 'hidden',
overflowY: 'auto',
maxHeight: 'calc(100% - 70px)',
},
},
queryList: {
listStyle: 'none',
margin: '0',
padding: '0',
},
queryListItem: {
'border-bottom-width': '1px',
'border-bottom-style': 'solid',
display: 'flex',
'justify-content': 'space-between',
padding: '5px 10px',
cursor: 'pointer',
'user-select': 'none',
'&:last-child': {
'border-bottom-width': 0,
},
overflow: 'hidden',
maxHeight: 47,
'border-bottom-color': map.BORDER_COLOR,
},
queryListItemKey: {
display: '-webkit-box',
boxOrient: 'vertical',
'-webkit-line-clamp': 2,
whiteSpace: 'normal',
overflow: 'hidden',
width: '100%',
maxWidth: 'calc(100% - 70px)',
wordBreak: 'break-all',
margin: 0,
},
queryListHeader: {
display: 'flex',
padding: 4,
flex: '0 0 auto',
'align-items': 'center',
'border-bottom-width': '1px',
'border-bottom-style': 'solid',
'border-color': map.LIST_BORDER_COLOR,
},
queryStatusWrapper: {
display: 'flex',
width: 'auto',
justifyContent: 'center',
alignItems: 'center',
margin: 0,
flex: '0 0 auto',
overflow: 'hidden',
},
queryType: {
marginRight: 4,
},
queryStatus: {
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
height: 22,
padding: '0 6px',
'border-radius': '3px',
'font-size': '0.7em',
'line-height': '1em',
'flex-shrink': 0,
fontWeight: 700,
'background-color': map.ACTION_TIME_BACK_COLOR,
color: map.ACTION_TIME_COLOR,
},
queryListItemSelected: {
'background-color': map.SELECTED_BACKGROUND_COLOR,
},
tabSelector: {
display: 'flex',
width: '100%',
justifyContent: 'flex-end',
overflow: 'hidden',
'& > *': {
flex: '0 1 auto',
},
},
srOnly: {
position: 'absolute',
width: 1,
height: 1,
padding: 0,
margin: '-1px',
overflow: 'hidden',
clip: 'rect(0,0,0,0)',
border: 0,
},
selectorButton: {
cursor: 'pointer',
position: 'relative',
height: '33px',
padding: '0 8px',
display: 'inline-flex',
alignItems: 'center',
color: map.TEXT_COLOR,
'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,
'& > *': {
display: '-webkit-box',
boxOrient: 'vertical',
'-webkit-line-clamp': 1,
overflow: 'hidden',
wordBreak: 'break-all',
'-webkit-box-pack': 'end',
paddingBottom: 0,
},
},
selectorButtonSmall: {
padding: '0px 8px',
'font-size': '0.8em',
},
selectorButtonSelected: {
'background-color': map.TAB_BACK_SELECTED_COLOR,
},
sortButton: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
flexFlow: 'row nowrap',
cursor: 'pointer',
position: 'relative',
padding: '0 8px',
color: map.TEXT_COLOR,
borderStyle: 'solid',
borderWidth: '1px',
borderRadius: '3px',
backgroundColor: map.TAB_BACK_COLOR,
borderColor: map.TAB_BORDER_COLOR,
height: 30,
fontSize: 12,
width: 64,
'&:active': {
backgroundColor: map.TAB_BACK_SELECTED_COLOR,
},
},
toggleButton: {
width: '24px',
height: '24px',
display: 'inline-block',
flex: '0 0 auto',
color: map.TEXT_PLACEHOLDER_COLOR,
cursor: 'pointer',
padding: 0,
fontSize: '0.7em',
letterSpacing: '-0.7px',
outline: 'none',
boxShadow: 'none',
fontWeight: '700',
border: 'none',
'&:hover': {
color: map.TEXT_COLOR,
},
backgroundColor: 'transparent',
'&[aria-pressed="true"]': {
color: map.BACKGROUND_COLOR,
backgroundColor: map.TEXT_COLOR,
},
'&[data-type="error"]': {
color: map.TEXT_COLOR,
backgroundColor: map.TOGGLE_BUTTON_ERROR,
},
},
queryForm: {
display: 'flex',
flexFlow: 'column nowrap',
},
sortBySection: {
display: 'flex',
padding: '0.4em',
'& label': {
display: 'flex',
flex: '0 0 auto',
whiteSpace: 'noWrap',
alignItems: 'center',
paddingRight: '0.4em',
},
'& > :last-child': {
flex: '0 0 auto',
marginLeft: '0.4em',
},
},
querySearch: {
maxWidth: '65%',
'background-color': map.BACKGROUND_COLOR,
display: 'flex',
alignItems: 'center',
flexFlow: 'row nowrap',
flex: '1 1 auto',
paddingRight: 6,
'& input': {
outline: 'none',
border: 'none',
width: '100%',
flex: '1 1 auto',
padding: '5px 10px',
'font-size': '1em',
position: 'relative',
fontFamily: '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,
},
'&::-webkit-search-cancel-button': appearanceNone,
},
},
closeButton: {
...appearanceNone,
border: 'none',
outline: 'none',
boxShadow: 'none',
display: 'block',
flex: '0 0 auto',
cursor: 'pointer',
background: 'transparent',
position: 'relative',
fontSize: 'inherit',
'&[data-invisible="1"]': {
visibility: 'hidden !important',
},
'&::after': {
content: '"\u00d7"',
display: 'block',
padding: 4,
fontSize: '1.2em',
color: map.TEXT_PLACEHOLDER_COLOR,
background: 'transparent',
},
'&:hover::after': {
color: map.TEXT_COLOR,
},
},
noApiFound: {
width: '100%',
textAlign: 'center',
color: map.TEXT_COLOR,
padding: '1.4em',
'& a': {
fontSize: 'inherit',
color: map.TEXT_COLOR,
textDecoration: 'underline',
},
},
searchSelectLabel: {
display: 'inline-block',
padding: 4,
borderLeft: '1px solid currentColor',
},
queryPreview: {
flex: '1 1 50%',
overflowX: 'hidden',
oveflowY: 'auto',
display: 'flex',
'flex-direction': 'column',
'overflow-y': 'hidden',
'& pre': {
border: 'inherit',
'border-radius': '3px',
'line-height': 'inherit',
color: 'inherit',
},
'background-color': map.BACKGROUND_COLOR,
},
previewHeader: {
flex: '0 0 30px',
padding: '5px 4px',
'align-items': 'center',
'border-bottom-width': '1px',
'border-bottom-style': 'solid',
'background-color': map.HEADER_BACKGROUND_COLOR,
'border-bottom-color': map.HEADER_BORDER_COLOR,
},
treeItemPin: {
'font-size': '0.7em',
'padding-left': '5px',
cursor: 'pointer',
'&:hover': {
'text-decoration': 'underline',
},
color: map.PIN_COLOR,
},
treeItemKey: {
color: map.TEXT_PLACEHOLDER_COLOR,
},
treeWrapper: {
overflowX: 'auto',
overflowY: 'auto',
padding: '0.5em 1em',
},
tabContent: {
display: 'block',
overflowY: 'auto',
padding: '0.5em 0',
color: map.TAB_CONTENT_COLOR,
'& h2': {
color: map.ULIST_STRONG_COLOR,
padding: '0.5em 1em',
fontWeight: 700,
},
'& h3': {
color: map.ULIST_STRONG_COLOR,
},
},
uList: {
listStyle: 'none',
padding: '0 0 0 1em',
color: map.ULIST_COLOR,
'& > li': {
listStyle: 'none',
},
'& > li::before': {
content: '"\\2022"',
display: 'inline-block',
paddingRight: '0.5em',
color: map.ULIST_DISC_COLOR,
fontSize: '0.8em',
},
'& strong': {
color: map.ULIST_STRONG_COLOR,
},
},
};
};
let themeSheet: StyleSheet;
const getDefaultThemeStyling = (theme: reduxThemes.Base16Theme) => {
if (themeSheet) {
themeSheet.detach();
}
themeSheet = jss
.createStyleSheet(getSheetFromColorMap(colorMap(theme)))
.attach();
return themeSheet.classes;
};
export const createStylingFromTheme = createStyling(getDefaultThemeStyling, {
defaultBase16: reduxThemes.nicinabox,
base16Themes: { ...reduxThemes },
});
export function createThemeState<S, A extends Action<unknown>>(
props: RtkQueryMonitorProps<S, A>
): StyleUtils {
const base16Theme =
getBase16Theme(props.theme, { ...reduxThemes }) ?? reduxThemes.nicinabox;
const theme = props.invertTheme ? invertTheme(props.theme) : props.theme;
const styling = createStylingFromTheme(theme);
return { base16Theme, styling, invertTheme: !!props.invertTheme };
}
const mockStyling = () => ({ className: '', style: {} });
export const StyleUtilsContext = createContext<StyleUtils>({
base16Theme: reduxThemes.nicinabox,
invertTheme: false,
styling: mockStyling,
});
export function getJsonTreeTheme(
base16Theme: reduxThemes.Base16Theme
): StylingConfig {
return {
extend: base16Theme,
nestedNode: ({ style }, keyPath, nodeType, expanded) => ({
style: {
...style,
whiteSpace: expanded ? 'inherit' : 'nowrap',
},
}),
nestedNodeItemString: ({ style }, keyPath, nodeType, expanded) => ({
style: {
...style,
display: expanded ? 'none' : 'inline',
},
}),
};
}