v2 event editor (#265)

* style: add cursor indicator in all blocks

* style: prevent reflows on width

* style: harmonise white range

* ux: focus elements on cursor nav

* ux: prevent focus on indicators

* refactor: convert to typescript

* fix: missing dependency

* chore: add linter rules for dependency arrays

* style: style editable component

* style: tweak input styles

* style: tweak switch styles

* style: style tweaks
This commit is contained in:
Carlos Valente
2022-12-08 22:22:08 +01:00
committed by GitHub
parent c56c5a636d
commit 6720626bd3
36 changed files with 193 additions and 100 deletions
+2 -1
View File
@@ -11,9 +11,10 @@
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:@typescript-eslint/recommended",
"eslint-config-prettier",
"plugin:@tanstack/eslint-plugin-query/recommended"
"plugin:@tanstack/eslint-plugin-query/recommended"
],
"plugins": [
"react",
+1
View File
@@ -68,6 +68,7 @@
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jest": "^27.0.4",
"eslint-plugin-react": "^7.31.8",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"eslint-plugin-testing-library": "^5.6.4",
"jsdom": "^20.0.0",
+4 -4
View File
@@ -1,4 +1,4 @@
import { Suspense, useCallback, useEffect } from 'react';
import { Suspense, useEffect } from 'react';
import { BrowserRouter } from 'react-router-dom';
import { ChakraProvider } from '@chakra-ui/react';
import { QueryClientProvider } from '@tanstack/react-query';
@@ -19,7 +19,7 @@ import('typeface-open-sans');
function App() {
const { isElectron, sendToElectron } = useElectronEvent();
const handleKeyPress = useCallback((event:KeyboardEvent) => {
const handleKeyPress = (event:KeyboardEvent) => {
// handle held key
if (event.repeat) return;
// check if the alt key is pressed
@@ -29,7 +29,7 @@ function App() {
sendToElectron('set-window', 'show-dev');
}
}
},[]);
};
useEffect(() => {
if (isElectron) {
@@ -40,7 +40,7 @@ function App() {
document.removeEventListener('keydown', handleKeyPress);
}
};
}, [handleKeyPress]);
}, []);
return (
<ChakraProvider resetCSS theme={theme}>
@@ -1,7 +1,11 @@
@use '../../../../theme/v2Styles' as *;
.delayInput {
display: flex;
gap: 8px;
gap: $element-spacing;
align-items: center;
color: $ontime-delay-text;
font-size: $text-body-size;
}
.inputField {
@@ -1,7 +1,6 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { Input } from '@chakra-ui/react';
import { clamp } from 'common/utils/math';
import PropTypes from 'prop-types';
import style from './DelayInput.module.scss';
@@ -81,8 +80,3 @@ export default function DelayInput(props: DelayInputProps) {
</label>
);
}
DelayInput.propTypes = {
submitHandler: PropTypes.func,
value: PropTypes.number,
};
@@ -1,6 +1,7 @@
import { useCallback, useRef } from 'react';
import { Input, Textarea } from '@chakra-ui/react';
import { EventEditorSubmitActions } from '../../../../features/event-editor/EventEditor';
import { Size } from '../../../models/UtilTypes';
import useReactiveTextInput from './useReactiveTextInput';
@@ -9,9 +10,9 @@ interface TextInputProps {
isTextArea?: boolean;
isFullHeight?: boolean;
size?: Size;
field: string;
field: EventEditorSubmitActions;
initialText?: string;
submitHandler: (field: string, newValue: string) => void;
submitHandler: (field: EventEditorSubmitActions, newValue: string) => void;
}
export default function TextInput(props: TextInputProps) {
@@ -20,7 +21,7 @@ export default function TextInput(props: TextInputProps) {
const submitCallback = useCallback((newValue: string) =>
submitHandler(field, newValue)
, [field]);
,[field, submitHandler]);
const textInputProps = useReactiveTextInput(initialText, submitCallback, { submitOnEnter: true });
const textAreaProps = useReactiveTextInput(initialText, submitCallback);
@@ -76,7 +76,7 @@ export default function useReactiveTextInput(
break;
}
},
[initialText, handleSubmit, text],
[initialText, options?.submitOnEnter, handleSubmit, text],
);
return {
+2 -2
View File
@@ -61,7 +61,7 @@ export const LoggingProvider = ({ children }: LoggingProviderProps) => {
return () => {
socket.off('logger');
};
}, [socket]);
}, []);
/**
* Utility function sends message over socket
@@ -86,7 +86,7 @@ export const LoggingProvider = ({ children }: LoggingProviderProps) => {
setLogData((currentLog) => currentLog.slice(1));
}
},
[logData.length, setLogData, socket],
[logData.length, setLogData],
);
/**
+1 -1
View File
@@ -60,7 +60,7 @@ export const useEventAction = () => {
emitError(`Error fetching data: ${error.message}`);
}
},
[_addEventMutation, emitError],
[_addEventMutation, emitError, queryClient],
);
/**
+1 -1
View File
@@ -14,5 +14,5 @@ export const useKeyDown = (callback: () => void, targetKey: string) => {
return () => {
document.removeEventListener('keydown', onKeyDown);
};
}, [onKeyDown]);
}, []);
};
+1 -1
View File
@@ -16,7 +16,7 @@ export default function useSubscription<T>(topic: string, initialState: T, reque
return () => {
socket.off(topic);
};
}, [requestString, socket, topic]);
}, [requestString, topic]);
return [state, setState] as const;
};
+4 -2
View File
@@ -1,3 +1,5 @@
export type TimeEntryField = 'timeStart' |'timeEnd' | 'durationOverride';
/**
* @description Milliseconds in a day
*/
@@ -12,7 +14,7 @@ export const calculateDuration = (start: number, end: number): number =>
/**
* @description Checks which field the value relates to
*/
export const handleTimeEntry = (field: string, val: number, timeStart: number, timeEnd: number): {start: number, end: number, durationOverride: boolean} => {
export const handleTimeEntry = (field: TimeEntryField, val: number, timeStart: number, timeEnd: number): {start: number, end: number, durationOverride: boolean} => {
let start = timeStart;
let end = timeEnd;
let durationOverride = false;
@@ -30,7 +32,7 @@ export const handleTimeEntry = (field: string, val: number, timeStart: number, t
/**
* @description Validates time entry
*/
export const validateEntry = (field: string, value: number, timeStart: number, timeEnd: number): { value: boolean, catch: string } => {
export const validateEntry = (field: TimeEntryField, value: number, timeStart: number, timeEnd: number): { value: boolean, catch: string } => {
const validate = { value: true, catch: '' };
// 1. if one of times is not entered, anything goes
@@ -1,12 +1,16 @@
@use '../../theme/ontimeColours' as *;
@use '../../theme/v2Styles' as *;
$menu-width: 48px;
$rundown-width: 46em;
$playback-width: 450px;
@mixin absolute-top-right($distance) {
position: absolute;
top: $distance;
right: $distance;
cursor: pointer;
color: #f2f2f2;
color: $ui-white;
}
.corner {
@@ -26,7 +30,7 @@
display: grid;
grid-template-rows: auto 1fr;
grid-template-columns: 48px 46em 450px auto;
grid-template-columns: $menu-width $rundown-width $playback-width auto;
grid-template-areas:
'sett even play info'
'sett even mess info';
@@ -50,7 +54,7 @@
.mainContainer {
height: 100%;
grid-template-rows: auto 1fr;
grid-template-columns: 48px 48em auto;
grid-template-columns: $menu-width $rundown-width auto;
.info {
visibility: hidden;
@@ -63,7 +67,7 @@
.mainContainer {
height: 100%;
grid-template-rows: 100%;
grid-template-columns: 48px 48em;
grid-template-columns: $menu-width $rundown-width;
grid-template-areas:
'sett even';
@@ -45,7 +45,6 @@
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 4px;
}
.left {
@@ -10,20 +10,23 @@ import { useEventAction } from 'common/hooks/useEventAction';
import { millisToMinutes } from 'common/utils/dateConfig';
import getDelayTo from 'common/utils/getDelayTo';
import { stringFromMillis } from 'common/utils/time';
import { calculateDuration, validateEntry } from 'common/utils/timesManager';
import { calculateDuration, TimeEntryField, validateEntry } from 'common/utils/timesManager';
import { useAtom } from 'jotai';
import CopyTag from '../../common/components/copy-tag/CopyTag';
import useRundown from '../../common/hooks-query/useRundown';
import { OntimeEvent } from '../../common/models/EventTypes';
import style from './EventEditor.module.scss';
export type EventEditorSubmitActions = keyof OntimeEvent | 'durationOverride';
export default function EventEditor() {
const [openId] = useAtom(editorEventId);
const { data } = useRundown();
const { emitWarning, emitError } = useContext(LoggingContext);
const { updateEvent } = useEventAction();
const [event, setEvent] = useState(null);
const [event, setEvent] = useState<OntimeEvent | null>(null);
const [delay, setDelay] = useState(0);
useEffect(() => {
@@ -33,28 +36,34 @@ export default function EventEditor() {
const eventIndex = data.findIndex((event) => event.id === openId);
if (eventIndex > -1) {
setDelay(getDelayTo(data, eventIndex));
setEvent(data[eventIndex]);
const event = data[eventIndex];
if (event.type === 'event') {
setDelay(getDelayTo(data, eventIndex));
setEvent(data[eventIndex] as OntimeEvent);
}
}
}, [data, event, openId]);
const handleSubmit = useCallback(
(field, value) => {
const newEventData = { id: event.id };
(field: EventEditorSubmitActions, value: any) => {
if (event === null) {
return;
}
const newEventData: Partial<OntimeEvent> = { id: event.id };
switch (field) {
case 'durationOverride': {
// duration defines timeEnd
newEventData.timeEnd = event.timeStart += value;
newEventData.timeEnd = event.timeStart += value as number;
break;
}
case 'timeStart': {
newEventData.duration = calculateDuration(value, event.timeEnd);
newEventData.timeStart = value;
newEventData.duration = calculateDuration(value as number, event.timeEnd);
newEventData.timeStart = value as number;
break;
}
case 'timeEnd': {
newEventData.duration = calculateDuration(event.timeStart, value);
newEventData.timeEnd = value;
newEventData.duration = calculateDuration(event.timeStart, value as number);
newEventData.timeEnd = value as number;
break;
}
default: {
@@ -73,22 +82,26 @@ export default function EventEditor() {
[emitError, event, updateEvent],
);
const timerValidationHandler = useCallback(
(entry, val) => {
const timerValidationHandler = useCallback((entry: TimeEntryField, val: number) => {
if (!event) {
return;
}
const valid = validateEntry(entry, val, event.timeStart, event.timeEnd);
if (!valid.value) {
emitWarning(`Time Input Warning: ${valid.catch}`);
}
return valid.value;
},
[emitWarning, event?.timeStart, event?.timeEnd],
[event, emitWarning],
);
const togglePublic = useCallback(
(currentValue) => {
const togglePublic = useCallback((currentValue: boolean) => {
if (!event) {
return;
}
updateEvent({ id: event.id, isPublic: !currentValue });
},
[event?.id, updateEvent],
[event, updateEvent],
);
if (!event) {
@@ -197,7 +210,7 @@ export default function EventEditor() {
handleChange={(value) => handleSubmit('colour', value)}
/>
<Button
rightIcon={<IoBan />}
leftIcon={<IoBan />}
onClick={() => handleSubmit('colour', '')}
variant='ontime-subtle'
size='sm'
+2 -2
View File
@@ -81,7 +81,7 @@ export default function MenuBar(props: MenuBarProps) {
}
}
},
[isElectron, isSettingsOpen, onSettingsClose, onSettingsOpen],
[isSettingsOpen, onSettingsClose, onSettingsOpen],
);
useEffect(() => {
@@ -93,7 +93,7 @@ export default function MenuBar(props: MenuBarProps) {
document.removeEventListener('keydown', handleKeyPress);
}
};
}, [handleKeyPress]);
}, [handleKeyPress, isElectron]);
return (
<VStack>
+1 -1
View File
@@ -41,7 +41,7 @@ const RundownMenu = () => {
break;
}
},
[toggleCursorLocked],
[addEvent, deleteAllEvents],
);
return (
+1 -1
View File
@@ -75,7 +75,7 @@ export default function AliasesModal() {
}
setSubmitting(false);
},
[aliases, refetch],
[aliases, emitError, refetch],
);
/**
+3 -3
View File
@@ -74,7 +74,7 @@ export default function Rundown(props) {
if (event.altKey && (!event.ctrlKey || !event.shiftKey)) {
// Arrow down
if (event.keyCode === 40) {
if (cursor < entries.length - 2) moveCursorDown();
if (cursor < entries.length - 1) moveCursorDown();
}
// Arrow up
if (event.keyCode === 38) {
@@ -121,7 +121,7 @@ export default function Rundown(props) {
block: 'nearest',
inline: 'start',
});
}, [cursor]);
}, [cursorRef]);
// if selected event
// or cursor settings changed
@@ -143,7 +143,7 @@ export default function Rundown(props) {
// move cursor
moveCursorTo(gotoIndex);
}
}, [data.selectedEventId, isCursorLocked, moveCursorTo]);
}, [data.selectedEventId, entries, isCursorLocked, moveCursorTo]);
// DND
const handleOnDragEnd = useCallback(
+13 -12
View File
@@ -132,16 +132,7 @@ export default function RundownEntry(props: RundownEntryProps) {
break;
}
},
[
addEvent,
calculateDuration,
data,
defaultPublic,
deleteEvent,
emitError,
startTimeIsLastEnd,
updateEvent,
],
[addEvent, data, defaultPublic, deleteEvent, emitError, moveCursorTo, openId, setOpenId, startTimeIsLastEnd, updateEvent],
);
if (data.type === 'event') {
@@ -168,9 +159,19 @@ export default function RundownEntry(props: RundownEntryProps) {
/>
);
} else if (data.type === 'block') {
return <BlockBlock index={index} data={data} actionHandler={actionHandler} />;
return <BlockBlock
index={index}
data={data}
hasCursor={hasCursor}
actionHandler={actionHandler}
/>;
} else if (data.type === 'delay') {
return <DelayBlock index={index} data={data} actionHandler={actionHandler} />;
return <DelayBlock
index={index}
data={data}
hasCursor={hasCursor}
actionHandler={actionHandler}
/>;
}
return null;
};
@@ -10,6 +10,7 @@ $block-text-color: $gray-50;
$block-bg: $gray-1200;
$block-box-shadow: rgba(0, 0, 0, 0.5) 0 0 3px 2px;
$secondary-block-height: 40px;
$block-cursor-color: $blue-400;
@mixin block-styling() {
box-sizing: content-box;
@@ -21,7 +22,7 @@ $secondary-block-height: 40px;
}
@mixin block-spacing() {
padding: 4px 10px 4px 2px;
padding: 4px 8px 4px 2px;
gap: 2px;
}
@@ -34,4 +35,8 @@ $secondary-block-height: 40px;
&:hover {
opacity: 1;
}
&:focus {
box-shadow: none;
outline: none;
}
}
@@ -8,6 +8,10 @@
grid-template-columns: 32px 1fr auto;
align-items: center;
height: $secondary-block-height;
&.hasCursor {
outline: 1px solid $block-cursor-color;
}
}
.drag {
@@ -1,7 +1,9 @@
import { useEffect, useRef } from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { IoReorderTwo } from '@react-icons/all-files/io5/IoReorderTwo';
import { OntimeBlock, OntimeEvent } from '../../../common/models/EventTypes';
import { cx } from '../../../common/utils/styleUtils';
import BlockActionMenu from '../event-block/composite/BlockActionMenu';
import { EventItemActions } from '../RundownEntry';
@@ -10,17 +12,30 @@ import style from './BlockBlock.module.scss';
interface BlockBlockProps {
index: number;
data: OntimeBlock;
hasCursor: boolean;
actionHandler: (action: EventItemActions, payload?: number | { field: keyof OntimeEvent, value: unknown }) => void;
}
export default function BlockBlock(props: BlockBlockProps) {
const { index, data, actionHandler } = props;
const { index, data, hasCursor, actionHandler } = props;
const onFocusRef = useRef<null | HTMLSpanElement>(null);
useEffect(() => {
if (hasCursor) {
onFocusRef?.current?.focus();
}
}, [hasCursor])
const blockClasses = cx([
style.block,
hasCursor ? style.hasCursor : null,
]);
return (
<Draggable key={data.id} draggableId={data.id} index={index}>
{(provided) => (
<div className={style.block} {...provided.draggableProps} ref={provided.innerRef}>
<span className={style.drag} {...provided.dragHandleProps}>
<div className={blockClasses} {...provided.draggableProps} ref={provided.innerRef}>
<span className={style.drag} {...provided.dragHandleProps} ref={onFocusRef}>
<IoReorderTwo />
</span>
<BlockActionMenu
@@ -10,6 +10,10 @@
align-items: center;
height: $secondary-block-height;
gap: 8px;
&.hasCursor {
outline: 1px solid $block-cursor-color;
}
}
.drag {
@@ -1,4 +1,4 @@
import { useCallback } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { Button, HStack } from '@chakra-ui/react';
import { IoCheckmark } from '@react-icons/all-files/io5/IoCheckmark';
@@ -8,6 +8,7 @@ import { useEventAction } from 'common/hooks/useEventAction';
import { millisToMinutes } from 'common/utils/dateConfig';
import { OntimeDelay, OntimeEvent } from '../../../common/models/EventTypes';
import { cx } from '../../../common/utils/styleUtils';
import BlockActionMenu from '../event-block/composite/BlockActionMenu';
import { EventItemActions } from '../RundownEntry';
@@ -16,12 +17,20 @@ import style from './DelayBlock.module.scss';
interface DelayBlockProps {
data: OntimeDelay,
index: number;
hasCursor: boolean;
actionHandler: (action: EventItemActions, payload?: number | { field: keyof OntimeEvent, value: unknown }) => void;
}
export default function DelayBlock(props: DelayBlockProps) {
const { data, index, actionHandler } = props;
const { data, index, hasCursor, actionHandler } = props;
const { applyDelay, updateEvent } = useEventAction();
const onFocusRef = useRef<null | HTMLSpanElement>(null);
useEffect(() => {
if (hasCursor) {
onFocusRef?.current?.focus();
}
}, [hasCursor])
const applyDelayHandler = useCallback(() => {
applyDelay(data.id);
@@ -39,13 +48,18 @@ export default function DelayBlock(props: DelayBlockProps) {
[data.id, updateEvent],
);
const blockClasses = cx([
style.delay,
hasCursor ? style.hasCursor : null,
]);
const delayValue = data.duration != null ? millisToMinutes(data.duration) : undefined;
return (
<Draggable key={data.id} draggableId={data.id} index={index}>
{(provided) => (
<div className={style.delay} {...provided.draggableProps} ref={provided.innerRef}>
<span className={style.drag} {...provided.dragHandleProps}>
<div className={blockClasses} {...provided.draggableProps} ref={provided.innerRef}>
<span className={style.drag} {...provided.dragHandleProps} ref={onFocusRef}>
<IoReorderTwo />
</span>
<DelayInput
@@ -24,7 +24,7 @@
}
&.hasCursor {
outline: 1px solid $blue-400;
outline: 1px solid $block-cursor-color;
}
&.skip {
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useState } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { Editable, EditableInput, EditablePreview, Tooltip } from '@chakra-ui/react';
import { IoOptions } from '@react-icons/all-files/io5/IoOptions';
@@ -81,6 +81,7 @@ export default function EventBlock(props: EventBlockProps) {
const [openId, setOpenId] = useAtom(editorEventId);
const { updateEvent } = useEventAction();
const [blockTitle, setBlockTitle] = useState<string>(title || '');
const onFocusRef = useRef<null | HTMLSpanElement>(null);
const binderColours = colour && getAccessibleColour(colour);
@@ -90,6 +91,12 @@ export default function EventBlock(props: EventBlockProps) {
setBlockTitle(title);
}, [title]);
useEffect(() => {
if (hasCursor) {
onFocusRef?.current?.focus();
}
}, [hasCursor]);
const handleTitle = useCallback(
(text: string) => {
if (text === title) {
@@ -101,7 +108,7 @@ export default function EventBlock(props: EventBlockProps) {
updateEvent({ id: eventId, title: cleanVal });
},
[updateEvent, title],
[title, updateEvent, eventId],
);
const eventIsPlaying = selected && playback === 'start';
@@ -133,7 +140,7 @@ export default function EventBlock(props: EventBlockProps) {
tabIndex={-1}
onClick={() => actionHandler('set-cursor', index)}
>
<span className={style.drag} {...provided.dragHandleProps}>
<span className={style.drag} {...provided.dragHandleProps} ref={onFocusRef}>
<IoReorderTwo />
</span>
{eventIndex}
@@ -184,6 +191,7 @@ export default function EventBlock(props: EventBlockProps) {
previousEnd={previousEnd}
/>
<Editable
variant='ontime'
value={blockTitle}
className={`${style.eventTitle} ${!title || title === '' ? style.noTitle : ''}`}
placeholder='Event title'
@@ -198,21 +206,25 @@ export default function EventBlock(props: EventBlockProps) {
<div className={selected ? style.progressBg : `${style.progressBg} ${style.hidden}`}>
<EventBlockProgressBar playback={playback} />
</div>
<div className={style.eventStatus}>
<div className={style.eventStatus} tabIndex={-1}
>
<Tooltip
label='Next event'
isDisabled={!next}
shouldWrapChildren {...tooltipProps}
{...tooltipProps}
>
<IoPlaySkipForward
className={`${style.statusIcon} ${next ? style.active : ''}`} />
<span>
<IoPlaySkipForward
className={`${style.statusIcon} ${next ? style.active : ''}`} />
</span>
</Tooltip>
<Tooltip
label={`${isPublic ? 'Event is public' : 'Event is private'}`}
{...tooltipProps}
shouldWrapChildren
>
<IoPeople className={`${style.statusIcon} ${isPublic ? style.active : ''}`} />
<span>
<IoPeople className={`${style.statusIcon} ${isPublic ? style.active : ''}`} />
</span>
</Tooltip>
</div>
</div>
@@ -58,7 +58,7 @@ export default function QuickAddBlock(props: QuickAddBlockProps) {
}
}
}, [addEvent, doPublic, doStartTime, emitError, previousId, previousEventId]);
}, [defaultPublic, previousId, previousEventId, addEvent, emitError]);
return (
<div className={style.quickAdd}>
+1 -1
View File
@@ -50,7 +50,7 @@ const withSocket = (Component) => {
socket.on('publicselected-id', (data) => {
setPublicSelectedId(data);
});
}, [socket]);
}, []);
const publicEvents = useMemo(() => {
+1
View File
@@ -20,6 +20,7 @@ $gray-900: #4c4c4c;
$gray-1000: #404040;
$gray-1050: #303030;
$gray-1100: #2d2d2d;
$gray-1250: #262626;
$gray-1200: #202020;
$gray-1300: #1a1a1a;
$gray-1350: #101010;
+14
View File
@@ -0,0 +1,14 @@
export const ontimeEditable = {
input: {
borderRadius: '3px',
width: '100%',
_focus: {
border: '1px solid #578AF4', // $blue-500
boxShadow: 'none',
},
},
preview: {
width: '100%',
border: '1px solid transparent', // $blue-500
},
};
+3 -3
View File
@@ -1,9 +1,9 @@
export const ontimeSelect = {
field: {
color: '#9d9d9d', // $gray-500
color: '#e2e2e2', // $gray-200
borderRadius: '3px',
fontWeight: '400',
background: '#2d2d2d', // $gray-1100
background: '#262626', // $gray-1100
border: '1px solid transparent',
_hover: {
background: '#404040', // $gray-1000
@@ -15,6 +15,6 @@ export const ontimeSelect = {
},
},
icon: {
color: '#9d9d9d', // $gray-500
color: '#e2e2e2', // $gray-200
},
};
+4
View File
@@ -2,9 +2,13 @@ export const ontimeSwitch = {
container: { },
track: {
background: '#2d2d2d', // $gray-1100
border: '1px solid transparent',
_checked: {
background: `#2B5ABC`, // $blue-700
},
_focus: {
border: '1px solid #578AF4', // $blue-500
}
},
thumb: {},
};
+3 -3
View File
@@ -1,14 +1,14 @@
const commonStyles = {
borderRadius: '3px',
fontWeight: '400',
backgroundColor: '#2d2d2d', // $gray-1100
backgroundColor: '#262626', // $gray-1250
color: '#e2e2e2', // $gray-200
border: '1px solid transparent',
_hover: {
backgroundColor: '#404040', // $gray-1000
backgroundColor: '#2d2d2d', // $gray-1100
},
_focus: {
backgroundColor: '#404040', // $gray-1000
backgroundColor: '#2d2d2d', // $gray-1000
color: '#f6f6f6', // $gray-50
border: '1px solid #578AF4', // $blue-500
},
+4 -9
View File
@@ -7,6 +7,7 @@ import {
ontimeButtonSubtleWhite,
} from './ontimeButton';
import { ontimeCheckboxOnDark } from './ontimeCheckbox';
import { ontimeEditable } from './ontimeEditable';
import { ontimeMenuOnDark } from './ontimeMenu';
import { ontimeSelect } from './ontimeSelect';
import { ontimeSwitch } from './ontimeSwitch';
@@ -36,19 +37,13 @@ const theme = extendTheme({
},
},
Editable: {
baseStyle: {
input: {
borderRadius: '2px',
width: '100%',
},
preview: {
width: '100%',
},
variants: {
'ontime': { ...ontimeEditable },
},
},
Input: {
baseStyle: {
borderRadius: '2px',
borderRadius: '3px',
border: '1px',
},
variants: {
+5
View File
@@ -2980,6 +2980,11 @@ eslint-plugin-jest@^27.0.4:
dependencies:
"@typescript-eslint/utils" "^5.10.0"
eslint-plugin-react-hooks@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3"
integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==
eslint-plugin-react@^7.31.8:
version "7.31.8"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz#3a4f80c10be1bcbc8197be9e8b641b2a3ef219bf"