diff --git a/.babelrc b/.babelrc index 990249e7..3eccdf35 100644 --- a/.babelrc +++ b/.babelrc @@ -7,6 +7,7 @@ "plugins": [ "@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-optional-chaining", - "@babel/plugin-proposal-nullish-coalescing-operator" + "@babel/plugin-proposal-nullish-coalescing-operator", + "@vanilla-extract/babel-plugin" ] } diff --git a/lib/makeWebpackConfig.js b/lib/makeWebpackConfig.js index 9a200f75..56defa7c 100644 --- a/lib/makeWebpackConfig.js +++ b/lib/makeWebpackConfig.js @@ -5,6 +5,8 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const FriendlyErrorsWebpackPlugin = require('@soda/friendly-errors-webpack-plugin'); const getStaticTypes = require('./getStaticTypes'); const makeDefaultWebpackConfig = require('./makeDefaultWebpackConfig'); +const { VanillaExtractPlugin } = require('@vanilla-extract/webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const playroomPath = path.resolve(__dirname, '..'); const includePaths = [ @@ -97,34 +99,24 @@ module.exports = async (playroomConfig, options) => { ], }, { - test: /\.less$/, - include: includePaths, + test: /\.vanilla\.css$/i, + include: playroomPath.includes('node_modules') + ? /node_modules\/playroom/ + : undefined, use: [ - require.resolve('style-loader'), + MiniCssExtractPlugin.loader, { loader: require.resolve('css-loader'), options: { - modules: { - mode: 'local', - localIdentName: '[name]__[local]--[contenthash:base64:5]', - }, - }, - }, - { - loader: require.resolve('postcss-loader'), - options: { - postcssOptions: { - plugins: [require('autoprefixer')()], - }, + url: false, }, }, - require.resolve('less-loader'), ], }, { test: /\.css$/, include: path.dirname(require.resolve('codemirror/package.json')), - use: [require.resolve('style-loader'), require.resolve('css-loader')], + use: [MiniCssExtractPlugin.loader, require.resolve('css-loader')], }, ], }, @@ -163,6 +155,8 @@ module.exports = async (playroomConfig, options) => { filename: 'preview/index.html', publicPath: '../', }), + new VanillaExtractPlugin(), + new MiniCssExtractPlugin({ ignoreOrder: true }), ...(options.production ? [] : [new FriendlyErrorsWebpackPlugin()]), ], devtool: !options.production && 'eval-source-map', diff --git a/package.json b/package.json index 598a87a4..84697000 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,11 @@ "@types/prettier": "^2.2.3", "@types/react": "^17.0.3", "@types/react-dom": "^17.0.2", - "autoprefixer": "^10.2.5", + "@vanilla-extract/babel-plugin": "^1.1.5", + "@vanilla-extract/css": "^1.7.0", + "@vanilla-extract/css-utils": "^0.1.2", + "@vanilla-extract/sprinkles": "^1.4.0", + "@vanilla-extract/webpack-plugin": "^2.1.8", "babel-loader": "^8.2.2", "classnames": "^2.3.1", "codemirror": "^5.59.4", @@ -93,16 +97,14 @@ "history": "^5.0.0", "html-webpack-plugin": "^5.3.1", "intersection-observer": "^0.12.0", - "less": "^4.1.1", - "less-loader": "^8.0.0", - "less-vars-loader": "^1.1.0", "localforage": "^1.9.0", "locate-path": "^6.0.0", "lodash": "^4.17.21", "lz-string": "^1.4.4", + "mini-css-extract-plugin": "^2.6.0", "parse-prop-types": "^0.3.0", + "polished": "^4.1.4", "portfinder": "^1.0.28", - "postcss-loader": "^5.2.0", "prettier": "^2.2.1", "prop-types": "^15.7.2", "query-string": "^6.14.1", @@ -112,7 +114,6 @@ "react-use": "^17.2.1", "read-pkg-up": "^7.0.1", "scope-eval": "^1.0.0", - "style-loader": "^3.2.1", "typescript": "^4.3.2", "url-join": "^4.0.1", "use-debounce": "^3.3.0", diff --git a/src/Playroom/Button/Button.css.ts b/src/Playroom/Button/Button.css.ts new file mode 100644 index 00000000..b450fef8 --- /dev/null +++ b/src/Playroom/Button/Button.css.ts @@ -0,0 +1,85 @@ +import { style, createVar } from '@vanilla-extract/css'; +import { calc } from '@vanilla-extract/css-utils'; +import { sprinkles, vars, colorPaletteVars } from '../sprinkles.css'; + +export const reset = style([ + sprinkles({ + boxSizing: 'border-box', + border: 0, + margin: 'none', + padding: 'none', + appearance: 'none', + userSelect: 'none', + position: 'relative', + cursor: 'pointer', + display: 'flex', + placeItems: 'center', + }), + { + background: 'transparent', + outline: 'none', + textDecoration: 'none', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + height: vars.touchableSize, + WebkitTapHighlightColor: 'transparent', + }, +]); + +const highlightColor = createVar(); + +export const base = style([ + sprinkles({ + borderRadius: 'large', + paddingY: 'none', + paddingX: 'large', + font: 'standard', + }), + { + vars: { + [highlightColor]: 'currentColor', + }, + color: highlightColor, + border: `1px solid ${colorPaletteVars.foreground.neutralSoft}`, + height: calc(vars.grid).multiply(9).toString(), + ':hover': { + vars: { + [highlightColor]: colorPaletteVars.foreground.accent, + }, + borderColor: highlightColor, + }, + ':active': { + transform: 'scale(0.98)', + }, + '::after': { + content: '', + position: 'absolute', + transform: 'translateY(-50%)', + minHeight: vars.touchableSize, + minWidth: vars.touchableSize, + left: calc(vars.grid).multiply(2).negate().toString(), + right: calc(vars.grid).multiply(2).negate().toString(), + height: '100%', + top: '50%', + }, + selectors: { + [`&:focus:not(:active):not(:hover):not([disabled])`]: { + boxShadow: colorPaletteVars.shadows.focus, + }, + }, + }, +]); + +export const positive = style({ + vars: { + [highlightColor]: `${colorPaletteVars.foreground.positive} !important`, + }, + borderColor: highlightColor, +}); + +export const iconContainer = style([ + sprinkles({ position: 'relative', paddingLeft: 'medium' }), + { + top: '1px', + }, +]); diff --git a/src/Playroom/Button/Button.less b/src/Playroom/Button/Button.less deleted file mode 100644 index b84ecaf1..00000000 --- a/src/Playroom/Button/Button.less +++ /dev/null @@ -1,70 +0,0 @@ -@import (reference) '../variables.less'; - -.reset { - box-sizing: border-box; - background: transparent; - border: 0; - margin: 0; - padding: 0; - outline: none; - appearance: none; - text-decoration: none; - white-space: nowrap; - text-overflow: ellipsis; - user-select: none; - position: relative; - height: @interaction-height; - -webkit-tap-highlight-color: transparent; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; -} - -.base { - border-radius: @radius-large; - padding: 0 (@grid * 3); - color: currentColor; - border: 1px solid @gray-3; - font: @text-standard; - height: @grid * 9; - - &:hover:not(.positive), - &.positive { - border-color: currentColor; - } - - &:after { - content: ''; - position: absolute; - transform: translateY(-50%); - min-height: @interaction-height; - min-width: @interaction-height; - left: -@grid * 2; - right: -@grid * 2; - height: 100%; - top: 50%; - } - - &:hover:not(.positive) { - color: @highlight; - } - - &:focus:not(:active):not(:hover):not(.positive) { - box-shadow: @focus-outline; - } - - &:active { - transform: scale(0.98); - } -} - -.positive { - color: @positive; -} - -.iconContainer { - position: relative; - top: 1px; - padding-left: 5px; -} diff --git a/src/Playroom/Button/Button.tsx b/src/Playroom/Button/Button.tsx index bd87d650..b2de8f89 100644 --- a/src/Playroom/Button/Button.tsx +++ b/src/Playroom/Button/Button.tsx @@ -1,8 +1,7 @@ import React, { ElementType, AllHTMLAttributes, ReactElement } from 'react'; import classnames from 'classnames'; -// @ts-ignore -import styles from './Button.less'; +import * as styles from './Button.css'; interface BaseProps { as?: ElementType; @@ -32,6 +31,7 @@ export const Button = ({ className={classnames(styles.reset, styles.base, { [styles.positive]: tone === 'positive', })} + disabled={tone === 'positive'} {...props} > {children} diff --git a/src/Playroom/CatchErrors/CatchErrors.css.ts b/src/Playroom/CatchErrors/CatchErrors.css.ts new file mode 100644 index 00000000..b3cf7246 --- /dev/null +++ b/src/Playroom/CatchErrors/CatchErrors.css.ts @@ -0,0 +1,8 @@ +import { sprinkles } from '../sprinkles.css'; + +export const root = sprinkles({ + position: 'fixed', + inset: 0, + overflow: 'auto', + padding: 'xxlarge', +}); diff --git a/src/Playroom/CatchErrors/CatchErrors.js b/src/Playroom/CatchErrors/CatchErrors.js deleted file mode 100644 index 962ac257..00000000 --- a/src/Playroom/CatchErrors/CatchErrors.js +++ /dev/null @@ -1,53 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { Text } from '../Text/Text'; -import { Strong } from '../Strong/Strong'; - -import styles from './CatchErrors.less'; - -export default class CatchErrors extends Component { - static propTypes = { - code: PropTypes.string.isRequired, - children: PropTypes.node.isRequired, - }; - - state = { - error: null, - invalidCode: null, - info: null, - }; - - componentDidCatch(error, info) { - const { code } = this.props; - this.setState({ invalidCode: code, error, info }); - } - - render() { - const { invalidCode, error, info } = this.state; - const { code, children } = this.props; - - if (code !== invalidCode) { - return children; - } - - // Ensure the stack only contains user-provided components - const componentStack = info.componentStack - .split('\n') - .filter((line) => /RenderCode/.test(line)) - .map((line) => line.replace(/ \(created by .*/g, '')); - - // Ignore the RenderCode container component - const lines = componentStack.slice(0, componentStack.length - 1); - - return ( -
- - {error.message} - {lines.map((line, i) => ( - {line} - ))} - -
- ); - } -} diff --git a/src/Playroom/CatchErrors/CatchErrors.less b/src/Playroom/CatchErrors/CatchErrors.less deleted file mode 100644 index 036d31b7..00000000 --- a/src/Playroom/CatchErrors/CatchErrors.less +++ /dev/null @@ -1,11 +0,0 @@ -@import (reference) '../variables.less'; - -.root { - position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; - overflow: auto; - padding: 20px; -} diff --git a/src/Playroom/CatchErrors/CatchErrors.tsx b/src/Playroom/CatchErrors/CatchErrors.tsx new file mode 100644 index 00000000..c2be882e --- /dev/null +++ b/src/Playroom/CatchErrors/CatchErrors.tsx @@ -0,0 +1,58 @@ +import React, { Component, ErrorInfo, ReactNode } from 'react'; +import { Text } from '../Text/Text'; +import { Strong } from '../Strong/Strong'; + +import * as styles from './CatchErrors.css'; + +interface Props { + code?: string; + children: ReactNode; +} +interface State { + invalidCode: string | null; + error: Error | null; + errorInfo: ErrorInfo | null; +} +export default class CatchErrors extends Component { + state: State = { + error: null, + invalidCode: null, + errorInfo: null, + }; + + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + const { code = null } = this.props; + this.setState({ invalidCode: code, error, errorInfo }); + } + + render() { + const { invalidCode, error, errorInfo } = this.state; + const { code, children } = this.props; + + if (code !== invalidCode || !error) { + return children; + } + + // Ensure the stack only contains user-provided components + const componentStack = errorInfo + ? errorInfo.componentStack + .split('\n') + .filter((line: string) => /RenderCode/.test(line)) + .map((line: string) => line.replace(/ \(created by .*/g, '')) + : []; + + // Ignore the RenderCode container component + const lines = componentStack.slice(0, componentStack.length - 1); + + return ( +
+ + {error.message} + {lines.map((line, i) => ( + {line} + ))} + +
+ ); + } +} diff --git a/src/Playroom/CodeEditor/CodeEditor.css.ts b/src/Playroom/CodeEditor/CodeEditor.css.ts new file mode 100644 index 00000000..eac416eb --- /dev/null +++ b/src/Playroom/CodeEditor/CodeEditor.css.ts @@ -0,0 +1,223 @@ +import { style, globalStyle, keyframes } from '@vanilla-extract/css'; +import { vars, colorPaletteVars, sprinkles } from '../sprinkles.css'; + +const minimumLineNumberWidth = '50px'; + +export const insertionPoint = style({ + backgroundColor: colorPaletteVars.background.selection, +}); + +const fadeIn = keyframes({ + '90%': { + opacity: 0, + }, + '100%': { + opacity: 1, + }, +}); +export const errorMarker = style([ + sprinkles({ + borderRadius: 'large', + position: 'relative', + textAlign: 'right', + opacity: 0, + }), + { + backgroundColor: colorPaletteVars.background.critical, + color: colorPaletteVars.foreground.critical, + minWidth: minimumLineNumberWidth, + marginRight: '4px', + paddingRight: '8px', + animationName: fadeIn, + animationDuration: '1s', + animationTimingFunction: 'ease', + animationIterationCount: 1, + animationFillMode: 'forwards', + }, +]); + +export const foldGutter = style({ + width: '1em', + padding: '0 8px', +}); + +export const foldOpen = style([ + sprinkles({ cursor: 'pointer' }), + { + '::after': { + content: '-', + }, + }, +]); + +export const foldFolded = style([ + sprinkles({ cursor: 'pointer' }), + { + '::after': { + content: '+', + color: colorPaletteVars.foreground.accent, + }, + }, +]); + +globalStyle('.react-codemirror2', { + height: '100%', + backgroundColor: colorPaletteVars.background.surface, +}); + +globalStyle('.CodeMirror', { + height: '100%', + width: '100%', + fontFamily: vars.font.family.code, + position: 'relative', + zIndex: 0, +}); + +globalStyle('.CodeMirror-gutters', { + minWidth: vars.codeGutterSize, + boxSizing: 'border-box', + paddingLeft: '8px', +}); + +globalStyle('.CodeMirror pre, .CodeMirror-linenumber', { + fontSize: '16px', +}); + +globalStyle('.CodeMirror-lines', { + padding: '16px 0', +}); + +globalStyle('.CodeMirror-hints', { + position: 'absolute', + zIndex: 10, + overflow: 'hidden', + listStyle: 'none', + margin: 0, + padding: 0, + boxShadow: colorPaletteVars.shadows.small, + borderRadius: vars.radii.medium, + backgroundColor: colorPaletteVars.background.surface, + fontSize: '90%', + lineHeight: '150%', + fontFamily: vars.font.family.code, + maxHeight: '20em', + overflowY: 'auto', +}); +globalStyle('[data-playroom-dark] .CodeMirror-hints', { + backgroundColor: colorPaletteVars.background.neutral, +}); + +globalStyle('.CodeMirror-hint', { + margin: 0, + padding: '4px 8px', + borderRadius: vars.radii.small, + whiteSpace: 'pre', + color: colorPaletteVars.code.text, + cursor: 'pointer', +}); + +globalStyle('li.CodeMirror-hint-active', { + backgroundColor: colorPaletteVars.background.accent, + color: colorPaletteVars.foreground.neutralInverted, +}); + +globalStyle('.CodeMirror-linenumbers', { + minWidth: minimumLineNumberWidth, +}); + +globalStyle('.CodeMirror-foldmarker', { + color: colorPaletteVars.foreground.accent, + fontFamily: 'arial', + cursor: 'pointer', + padding: `0 ${vars.grid}`, +}); + +globalStyle('.cm-s-neo.CodeMirror', { + backgroundColor: colorPaletteVars.background.surface, + color: colorPaletteVars.code.text, +}); + +globalStyle('.cm-s-neo .CodeMirror-cursor', { + backgroundColor: colorPaletteVars.foreground.neutral, + width: '2px', +}); + +globalStyle('.cm-s-neo .CodeMirror-gutters', { + backgroundColor: colorPaletteVars.background.surface, + border: 'none', +}); + +globalStyle('.cm-s-neo .CodeMirror-gutters::after', { + content: '""', + backgroundColor: colorPaletteVars.background.surface, + position: 'absolute', + right: '2px', + height: '100%', + boxShadow: `0 0 10px 5px ${colorPaletteVars.background.surface}`, +}); + +globalStyle('.cm-s-neo .CodeMirror-selected', { + background: colorPaletteVars.background.selection, +}); + +globalStyle('.cm-s-neo .CodeMirror-activeline-background', { + background: 'transparent', +}); + +globalStyle('.cm-s-neo .CodeMirror-guttermarker-subtle', { + display: 'flex', + justifyContent: 'center', + color: colorPaletteVars.foreground.neutral, + transition: vars.transition.fast, +}); + +globalStyle( + `.cm-s-neo .CodeMirror-guttermarker-subtle:not(:hover):not(${foldFolded})`, + { + color: colorPaletteVars.foreground.neutralSoft, + } +); + +globalStyle('.cm-s-neo .CodeMirror-linenumber', { + minWidth: minimumLineNumberWidth, + color: colorPaletteVars.foreground.neutral, + transition: vars.transition.fast, +}); + +globalStyle( + '.cm-s-neo .CodeMirror-linenumber:not(:hover):not(.cm-s-neo .CodeMirror-activeline .CodeMirror-linenumber)', + { + color: colorPaletteVars.foreground.neutralSoft, + } +); + +globalStyle('.cm-s-neo .cm-tag', { + color: colorPaletteVars.code.tag, +}); + +globalStyle( + [ + '.cm-s-neo .cm-attribute', + '.cm-s-neo .cm-keyword', + '.cm-s-neo .cm-property', + ].join(','), + { + color: colorPaletteVars.code.attribute, + } +); + +globalStyle('.cm-s-neo .cm-string', { + color: colorPaletteVars.code.string, +}); + +globalStyle('.cm-s-neo .cm-atom', { + color: colorPaletteVars.code.atom, +}); + +globalStyle('.cm-s-neo .cm-variable', { + color: colorPaletteVars.code.variable, +}); + +globalStyle('.cm-s-neo .cm-number', { + color: colorPaletteVars.code.number, +}); diff --git a/src/Playroom/CodeEditor/CodeEditor.less b/src/Playroom/CodeEditor/CodeEditor.less deleted file mode 100644 index b5690265..00000000 --- a/src/Playroom/CodeEditor/CodeEditor.less +++ /dev/null @@ -1,187 +0,0 @@ -@import (reference) '../variables.less'; - -@minimumLineNumberWidth: 50px; -@lineNumberOpacity: 0.4; - -.insertionPoint { - background-color: @code-selection; -} - -.errorMarker { - @keyframes fadeIn { - 90% { - opacity: 0; - } - 100% { - opacity: 1; - } - } - - border-radius: @radius-large; - background-color: @critical-light; - color: @critical-dark; - position: relative; - min-width: @minimumLineNumberWidth; - margin-right: 4px; - text-align: right; - opacity: 0; - padding-right: 8px; - animation-name: fadeIn; - animation-duration: 1s; - animation-timing-function: ease; - animation-iteration-count: 1; - animation-fill-mode: forwards; -} - -.foldGutter { - width: 1em; - padding: 0 8px; -} -.foldOpen, -.foldFolded { - cursor: pointer; -} -.foldOpen::after { - content: '-'; -} -.foldFolded::after { - content: '+'; - color: @highlight; -} - -:global { - .react-codemirror2 { - height: 100%; - background-color: @code-background; - } - - .CodeMirror { - height: 100%; - width: 100%; - font-family: @code-font-family; - position: relative; - z-index: 0; - } - - .CodeMirror-gutters { - min-width: @code-gutter-size; - box-sizing: border-box; - padding-left: 8px; - } - - .CodeMirror pre, - .CodeMirror-linenumber { - font-size: 16px; - } - - .CodeMirror-lines { - padding: 16px 0; - } - - .CodeMirror-hints { - position: absolute; - z-index: 10; - overflow: hidden; - list-style: none; - margin: 0; - padding: 0; - box-shadow: @shadow-small; - border-radius: @radius-medium; - background-color: @code-background; - font-size: 90%; - line-height: 150%; - font-family: @code-font-family; - max-height: 20em; - overflow-y: auto; - } - - .CodeMirror-hint { - margin: 0; - padding: 4px 8px; - border-radius: @radius-small; - white-space: pre; - color: @black; - cursor: pointer; - } - - li.CodeMirror-hint-active { - background-color: @code-hint-bg; - color: @code-hint-fg; - } - - .CodeMirror-linenumbers { - min-width: @minimumLineNumberWidth; - } - - .CodeMirror-foldmarker { - color: @highlight; - font-family: arial; - cursor: pointer; - padding: 0 @grid; - } - - .cm-s-neo { - &.CodeMirror { - background-color: @code-background; - } - .CodeMirror-cursor { - background-color: @black; - width: 2px; - } - .CodeMirror-gutters { - background-color: @code-background; - border: none; - &::after { - content: ''; - background-color: @code-background; - position: absolute; - right: 0; - height: 100%; - box-shadow: 0 0 10px 5px @code-background; - } - } - .CodeMirror-selected { - background: @code-selection; - } - - .CodeMirror-activeline-background { - background: transparent; - } - - .CodeMirror-guttermarker-subtle { - display: flex; - justify-content: center; - color: @gray-4; - transition: @transition-fast; - &:not(:hover):not(:local(.foldFolded)) { - opacity: @lineNumberOpacity; - } - } - - .CodeMirror-linenumber { - min-width: @minimumLineNumberWidth; - color: @gray-4; - transition: @transition-fast; - &:not(:hover):not(.cm-s-neo - .CodeMirror-activeline - .CodeMirror-linenumber) { - opacity: @lineNumberOpacity; - } - } - .cm-tag { - color: @code-format-tag; - } - .cm-attribute { - color: @code-format-attribute; - } - .cm-string { - color: @code-format-string; - } - .cm-atom { - color: @code-format-atom; - } - .cm-variable { - color: @code-format-variable; - } - } -} diff --git a/src/Playroom/CodeEditor/CodeEditor.tsx b/src/Playroom/CodeEditor/CodeEditor.tsx index 67c1bb1e..7ab53e1f 100644 --- a/src/Playroom/CodeEditor/CodeEditor.tsx +++ b/src/Playroom/CodeEditor/CodeEditor.tsx @@ -8,8 +8,7 @@ import { StoreContext, CursorPosition } from '../../StoreContext/StoreContext'; import { formatCode as format } from '../../utils/formatting'; import { compileJsx } from '../../utils/compileJsx'; -// @ts-ignore -import styles from './CodeEditor.less'; +import * as styles from './CodeEditor.css'; import { UnControlled as ReactCodeMirror } from 'react-codemirror2'; import 'codemirror/mode/jsx/jsx'; @@ -79,7 +78,7 @@ const validateCode = (editorInstance: Editor, code: string) => { if (lineNumber) { const marker = document.createElement('div'); - marker.classList.add(styles.errorMarker); + marker.setAttribute('class', styles.errorMarker); marker.setAttribute( 'title', // Remove our wrapping Fragment from error message diff --git a/src/Playroom/Divider/Divider.css.ts b/src/Playroom/Divider/Divider.css.ts new file mode 100644 index 00000000..faac2e44 --- /dev/null +++ b/src/Playroom/Divider/Divider.css.ts @@ -0,0 +1,16 @@ +import { style } from '@vanilla-extract/css'; +import { sprinkles, colorPaletteVars } from '../sprinkles.css'; + +export const root = sprinkles({ + position: 'relative', +}); + +export const divider = style([ + sprinkles({ + position: 'absolute', + width: 'full', + }), + { + borderTop: `1px solid ${colorPaletteVars.border.standard}`, + }, +]); diff --git a/src/Playroom/Divider/Divider.less b/src/Playroom/Divider/Divider.less deleted file mode 100644 index 01f70fbe..00000000 --- a/src/Playroom/Divider/Divider.less +++ /dev/null @@ -1,11 +0,0 @@ -@import (reference) '../variables.less'; - -.root { - position: relative; -} - -.divider { - position: absolute; - width: 100%; - border-top: 1px solid @gray-2; -} diff --git a/src/Playroom/Divider/Divider.tsx b/src/Playroom/Divider/Divider.tsx index 1fa82421..97d1c6c9 100644 --- a/src/Playroom/Divider/Divider.tsx +++ b/src/Playroom/Divider/Divider.tsx @@ -1,7 +1,6 @@ import React from 'react'; -// @ts-ignore -import styles from './Divider.less'; +import * as styles from './Divider.css'; export const Divider = () => (
diff --git a/src/Playroom/Frames/Frames.css.ts b/src/Playroom/Frames/Frames.css.ts new file mode 100644 index 00000000..a5ef0cb9 --- /dev/null +++ b/src/Playroom/Frames/Frames.css.ts @@ -0,0 +1,83 @@ +import { style } from '@vanilla-extract/css'; +import { sprinkles } from '../sprinkles.css'; + +export const root = style([ + sprinkles({ + height: 'full', + width: 'full', + whiteSpace: 'nowrap', + display: 'flex', + boxSizing: 'border-box', + paddingY: 'gutter', + paddingLeft: 'gutter', + textAlign: 'center', + }), + { + overflowX: 'auto', + overflowY: 'hidden', + // // Simulate centering when fewer frames than viewport width. + '::before': { + content: '""', + flex: 1, + }, + '::after': { + content: '""', + flex: 1, + }, + }, +]); + +export const frameContainer = style([ + sprinkles({ + position: 'relative', + height: 'full', + textAlign: 'left', + display: 'flex', + flexDirection: 'column', + paddingRight: 'gutter', + }), + {}, +]); + +export const frame = style([ + sprinkles({ position: 'relative', height: 'full', border: 0 }), + { + flexGrow: 1, + }, +]); + +export const frameBorder = style([ + sprinkles({ + position: 'absolute', + inset: 0, + boxShadow: 'small', + transition: 'medium', + pointerEvents: 'none', + }), + { + selectors: { + [`&:not(:hover)`]: { + opacity: 0.8, + }, + }, + }, +]); + +const frameNameHeight = '30px'; +export const frameName = style([ + sprinkles({ + display: 'flex', + alignItems: 'center', + transition: 'medium', + }), + { + flex: `0 0 ${frameNameHeight}`, + height: frameNameHeight, + marginBottom: '-10px', + selectors: { + [`${frameContainer}:not(:hover) &`]: { + opacity: 0.3, + }, + }, + }, +]); diff --git a/src/Playroom/Frames/Frames.less b/src/Playroom/Frames/Frames.less deleted file mode 100644 index 285d603a..00000000 --- a/src/Playroom/Frames/Frames.less +++ /dev/null @@ -1,69 +0,0 @@ -@import (reference) '../variables.less'; - -.root { - box-sizing: border-box; - width: 100%; - height: 100%; - overflow-x: auto; - overflow-y: hidden; - white-space: nowrap; - padding: @preview-padding 0 (@preview-padding - 10px) @preview-padding; - text-align: center; - display: flex; - - // Simulate centering when fewer frames than viewport width. - &::before, - &::after { - content: ''; - flex: 1; - } -} - -.frameContainer { - position: relative; - height: 100%; - text-align: left; - display: flex; - flex-direction: column; - padding-right: @preview-padding; -} - -.frame { - position: relative; - flex-grow: 1; -} - -.frameBorder { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - box-shadow: @shadow-small; - transition: @transition-medium; - pointer-events: none; - - .frameContainer:not(:hover) & { - opacity: 0.8; - } -} - -.frameName { - @frame-name-height: 30px; - - flex: 0 0 @frame-name-height; - height: @frame-name-height; - transition: @transition-medium; - display: flex; - align-items: center; - - .frameContainer:not(:hover) & { - opacity: @preview-inactive-label-opacity; - } -} - -.frame { - height: 100%; - border: 0; - background-color: @white; -} diff --git a/src/Playroom/Frames/Frames.tsx b/src/Playroom/Frames/Frames.tsx index 2fd3b93d..5b4af434 100644 --- a/src/Playroom/Frames/Frames.tsx +++ b/src/Playroom/Frames/Frames.tsx @@ -8,8 +8,7 @@ import { Text } from '../Text/Text'; import playroomConfig from '../../config'; import frameSrc from './frameSrc'; -// @ts-ignore -import styles from './Frames.less'; +import * as styles from './Frames.css'; interface FramesProps { code: string; diff --git a/src/Playroom/FramesPanel/FramesPanel.css.ts b/src/Playroom/FramesPanel/FramesPanel.css.ts new file mode 100644 index 00000000..8a0ed3ba --- /dev/null +++ b/src/Playroom/FramesPanel/FramesPanel.css.ts @@ -0,0 +1,145 @@ +import { calc } from '@vanilla-extract/css-utils'; +import { globalStyle, style } from '@vanilla-extract/css'; +import { colorPaletteVars, sprinkles, vars } from '../sprinkles.css'; + +export const title = sprinkles({ + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + marginBottom: 'medium', +}); + +export const reset = style([ + sprinkles({ + position: 'relative', + font: 'small', + border: 0, + padding: 'medium', + appearance: 'none', + }), + { + color: 'currentColor', + backgroundColor: 'transparent', + outline: 'none', + textDecoration: 'underline', + margin: calc(vars.space.medium).negate().toString(), + '::before': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + borderRadius: vars.radii.large, + boxShadow: colorPaletteVars.shadows.focus, + cursor: 'pointer', + opacity: 0, + transform: 'scale(0.8)', + transition: vars.transition.medium, + }, + selectors: { + [`&:focus::before, &:hover::before`]: { + opacity: 1, + transform: 'scale(1)', + }, + }, + }, +]); + +export const label = style([ + sprinkles({ + position: 'relative', + display: 'flex', + alignItems: 'center', + cursor: 'pointer', + userSelect: 'none', + }), + { + height: calc(vars.grid).multiply(9).toString(), + }, +]); + +const checkboxSize = '20px'; +export const checkbox = style([ + sprinkles({ + position: 'absolute', + margin: 'none', + left: 0, + right: 0, + opacity: 0, + pointerEvents: 'none', + }), + { + height: checkboxSize, + width: checkboxSize, + }, +]); + +const checkboxPadding = 'xxsmall'; +export const fakeCheckbox = style([ + sprinkles({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + position: 'relative', + borderRadius: 'large', + marginRight: 'large', + padding: checkboxPadding, + }), + { + flexGrow: 0, + flexShrink: 0, + height: calc(checkboxSize) + .subtract(calc(vars.space[checkboxPadding]).multiply(2)) + .toString(), + width: calc(checkboxSize) + .subtract(calc(vars.space[checkboxPadding]).multiply(2)) + .toString(), + '::before': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + borderRadius: vars.radii.medium, + boxShadow: colorPaletteVars.shadows.focus, + transition: vars.transition.medium, + opacity: 0, + transform: 'scale(0.5)', + }, + '::after': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + borderRadius: vars.radii.medium, + boxShadow: 'inset 0 0 0px 1px currentColor', + background: colorPaletteVars.background.surface, + }, + selectors: { + [`${checkbox}:hover:not(:focus) ~ &::before, ${checkbox}:focus ~ &::before`]: { + opacity: 1, + transform: 'scale(1)', + }, + }, + }, +]); + +globalStyle(`${fakeCheckbox} > svg`, { + height: '100%', + width: '100%', + opacity: 0, + transform: 'scale(0.6)', + transition: vars.transition.fast, + transitionDelay: '0.1s, 0.3s', + zIndex: 1, +}); + +globalStyle(`${checkbox}:checked ~ ${fakeCheckbox} > svg `, { + opacity: 1, + transform: 'none', + transition: vars.transition.fast, +}); diff --git a/src/Playroom/FramesPanel/FramesPanel.less b/src/Playroom/FramesPanel/FramesPanel.less deleted file mode 100644 index 7616050f..00000000 --- a/src/Playroom/FramesPanel/FramesPanel.less +++ /dev/null @@ -1,114 +0,0 @@ -@import (reference) '../variables.less'; - -.title { - margin-bottom: 10px; - display: flex; - justify-content: space-between; - align-items: center; -} - -.reset { - font: @text-small; - color: currentColor; - margin: -10px; - padding: 10px; - border: 0; - background-color: transparent; - appearance: none; - outline: none; - text-decoration: underline; - position: relative; - - &:before { - content: ''; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - border-radius: @radius-large; - background-color: currentColor; - cursor: pointer; - opacity: 0; - transform: scale(0.8); - transition: @transition-medium; - - :focus&, - :hover& { - opacity: 0.1; - transform: scale(1); - } - } -} - -.label { - position: relative; - display: flex; - align-items: center; - height: @grid * 9; - cursor: pointer; - user-select: none; -} - -@checkbox-size: 20px; -.checkbox { - position: absolute; - left: 0; - margin: 0; - right: 0; - height: @checkbox-size; - width: @checkbox-size; - opacity: 0; - pointer-events: none; -} - -.fakeCheckbox { - @padding-size: 2px; - display: flex; - align-items: center; - justify-content: center; - flex-grow: 0; - flex-shrink: 0; - height: @checkbox-size - (@padding-size * 2); - width: @checkbox-size - (@padding-size * 2); - padding: @padding-size; - margin-right: 15px; - position: relative; - border-radius: @radius-large; - box-shadow: inset 0 0 0px 1px currentColor; - - &::after { - content: ''; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - border-radius: @radius-medium; - box-shadow: 0 0 0 4px currentColor; - transition: @transition-fast; - opacity: 0; - transform: scale(0.5); - - .checkbox:hover:not(:focus) ~ &, - .checkbox:focus ~ & { - opacity: 0.1; - transform: scale(1); - } - } - - > :global(svg) { - height: 100%; - width: 100%; - opacity: 0; - transform: scale(0.6); - transition: opacity @transition-speed-fast ease, transform 0s; - transition-delay: 0.1s, 0.3s; - - .checkbox:checked ~ & { - opacity: 1; - transform: none; - transition: @transition-fast; - } - } -} diff --git a/src/Playroom/FramesPanel/FramesPanel.tsx b/src/Playroom/FramesPanel/FramesPanel.tsx index 7c3625ab..1c37eb15 100644 --- a/src/Playroom/FramesPanel/FramesPanel.tsx +++ b/src/Playroom/FramesPanel/FramesPanel.tsx @@ -6,8 +6,7 @@ import { StoreContext } from '../../StoreContext/StoreContext'; import { Stack } from '../Stack/Stack'; import { Text } from '../Text/Text'; -// @ts-ignore -import styles from './FramesPanel.less'; +import * as styles from './FramesPanel.css'; interface FramesPanelProps { availableWidths: number[]; diff --git a/src/Playroom/Heading/Heading.css.ts b/src/Playroom/Heading/Heading.css.ts new file mode 100644 index 00000000..0f5f3ff8 --- /dev/null +++ b/src/Playroom/Heading/Heading.css.ts @@ -0,0 +1,27 @@ +import { sprinkles, vars, colorPaletteVars } from '../sprinkles.css'; +import { style } from '@vanilla-extract/css'; + +export const base = style([ + sprinkles({ + margin: 'none', + fontWeight: 'strong', + }), + { + color: colorPaletteVars.foreground.neutral, + fontFamily: vars.font.family.standard, + }, +]); + +export const level1 = style({ + fontSize: '36px', +}); +export const level2 = style({ + fontSize: '24px', +}); +export const level3 = style({ + fontSize: '16px', +}); + +export const weak = sprinkles({ + fontWeight: 'weak', +}); diff --git a/src/Playroom/Heading/Heading.less b/src/Playroom/Heading/Heading.less deleted file mode 100644 index 30312301..00000000 --- a/src/Playroom/Heading/Heading.less +++ /dev/null @@ -1,20 +0,0 @@ -@import (reference) '../variables.less'; - -.base { - margin: 0; - color: @text-neutral; -} - -.level1 { - font: @bold 36px @typography-family; -} -.level2 { - font: @bold 24px @typography-family; -} -.level3 { - font: @bold 16px @typography-family; -} - -.weak { - font-weight: @weak; -} diff --git a/src/Playroom/Heading/Heading.tsx b/src/Playroom/Heading/Heading.tsx index 36c7a0a7..7653ce16 100644 --- a/src/Playroom/Heading/Heading.tsx +++ b/src/Playroom/Heading/Heading.tsx @@ -1,8 +1,7 @@ import React, { ElementType, ReactNode } from 'react'; import classnames from 'classnames'; -// @ts-ignore -import styles from './Heading.less'; +import * as styles from './Heading.css'; interface Props { level: '1' | '2' | '3'; diff --git a/src/Playroom/Inline/Inline.css.ts b/src/Playroom/Inline/Inline.css.ts new file mode 100644 index 00000000..03ae3579 --- /dev/null +++ b/src/Playroom/Inline/Inline.css.ts @@ -0,0 +1,57 @@ +import { calc } from '@vanilla-extract/css-utils'; +import { createVar, style } from '@vanilla-extract/css'; +import { sprinkles, vars } from '../sprinkles.css'; + +const size = createVar(); + +export const root = style([ + sprinkles({ + display: 'flex', + flexWrap: 'wrap', + }), + { + marginTop: calc(size).negate().toString(), + marginLeft: calc(size).negate().toString(), + }, +]); + +export const item = style({ + paddingTop: size, + paddingLeft: size, +}); + +export const xxsmall = style({ + vars: { + [size]: vars.grid, + }, +}); + +export const xsmall = style({ + vars: { + [size]: calc(vars.grid).multiply(2).toString(), + }, +}); + +export const small = style({ + vars: { + [size]: calc(vars.grid).multiply(3).toString(), + }, +}); + +export const medium = style({ + vars: { + [size]: calc(vars.grid).multiply(4).toString(), + }, +}); + +export const large = style({ + vars: { + [size]: calc(vars.grid).multiply(5).toString(), + }, +}); + +export const xlarge = style({ + vars: { + [size]: calc(vars.grid).multiply(6).toString(), + }, +}); diff --git a/src/Playroom/Inline/Inline.less b/src/Playroom/Inline/Inline.less deleted file mode 100644 index 1ec12b31..00000000 --- a/src/Playroom/Inline/Inline.less +++ /dev/null @@ -1,58 +0,0 @@ -@import (reference) '../variables.less'; - -.root { - display: flex; - flex-wrap: wrap; - - &.xxsmall { - margin-top: -@grid; - margin-left: -@grid; - } - &.xsmall { - margin-top: -@grid * 2; - margin-left: -@grid * 2; - } - &.small { - margin-top: -@grid * 3; - margin-left: -@grid * 3; - } - &.medium { - margin-top: -@grid * 4; - margin-left: -@grid * 4; - } - &.large { - margin-top: -@grid * 6; - margin-left: -@grid * 6; - } - &.xlarge { - margin-top: -@grid * 12; - margin-left: -@grid * 12; - } -} - -.inlineItem { - &.xxsmall { - padding-left: @grid; - padding-top: @grid; - } - &.xsmall { - padding-left: @grid * 2; - padding-top: @grid * 2; - } - &.small { - padding-left: @grid * 3; - padding-top: @grid * 3; - } - &.medium { - padding-left: @grid * 4; - padding-top: @grid * 4; - } - &.large { - padding-left: @grid * 6; - padding-top: @grid * 6; - } - &.xlarge { - padding-left: @grid * 12; - padding-top: @grid * 12; - } -} diff --git a/src/Playroom/Inline/Inline.tsx b/src/Playroom/Inline/Inline.tsx index 40b275bb..21e745a1 100644 --- a/src/Playroom/Inline/Inline.tsx +++ b/src/Playroom/Inline/Inline.tsx @@ -1,8 +1,7 @@ import React, { ReactElement, Children } from 'react'; import classnames from 'classnames'; -// @ts-ignore -import styles from './Inline.less'; +import * as styles from './Inline.css'; interface ReactNodeArray extends Array {} type ReactNodeNoStrings = @@ -24,28 +23,12 @@ interface Props { | 'xlarge'; } -export const Inline = ({ children, space }: Props) => { - const items = Children.toArray(children); - - const itemSizeClass = classnames({ - [styles.xxsmall]: space === 'xxsmall', - [styles.xsmall]: space === 'xsmall', - [styles.small]: space === 'small', - [styles.medium]: space === 'medium', - [styles.large]: space === 'large', - [styles.xlarge]: space === 'xlarge', - }); - - return ( -
- {items.map((item, index) => ( -
- {item} -
- ))} -
- ); -}; +export const Inline = ({ children, space }: Props) => ( +
+ {Children.toArray(children).map((item, index) => ( +
+ {item} +
+ ))} +
+); diff --git a/src/Playroom/Playroom.css.ts b/src/Playroom/Playroom.css.ts new file mode 100644 index 00000000..84c166f0 --- /dev/null +++ b/src/Playroom/Playroom.css.ts @@ -0,0 +1,150 @@ +import { style, globalStyle } from '@vanilla-extract/css'; +import { sprinkles, vars, colorPaletteVars } from './sprinkles.css'; +import { toolbarItemSize } from './ToolbarItem/ToolbarItem.css'; + +globalStyle('html', { + width: '100%', + height: '100%', + overflow: 'hidden', + backgroundColor: colorPaletteVars.background.body, +}); + +globalStyle('html[data-playroom-dark]', { + colorScheme: 'dark', +}); + +globalStyle('body', { + margin: 0, +}); + +export const root = sprinkles({ + height: 'viewport', + width: 'viewport', +}); + +export const previewContainer = sprinkles({ + position: 'absolute', + inset: 0, +}); + +export const resizeableContainer = style([ + sprinkles({ + bottom: 0, + right: 0, + overflow: 'hidden', + boxShadow: 'small', + transition: 'slow', + }), + // @ts-expect-error Shouldnt need to but types do not like `!important` + { + position: 'absolute !important', // override re-resizeable's inline style + }, +]); + +export const resizeableContainer_isHidden = style({}); + +export const resizeableContainer_isRight = style([ + sprinkles({ + top: 0, + }), + { + maxWidth: '90vw', + selectors: { + [`&${resizeableContainer_isHidden}`]: { + transform: 'translateX(100%)', + }, + }, + }, +]); + +export const resizeableContainer_isBottom = style([ + sprinkles({ + left: 0, + }), + { + maxHeight: '90vh', + selectors: { + [`&${resizeableContainer_isHidden}`]: { + transform: 'translateY(100%)', + }, + }, + }, +]); + +export const isBottom = style({}); + +export const toggleEditorContainer = style([ + sprinkles({ + position: 'absolute', + bottom: 0, + right: 0, + display: 'flex', + justifyContent: 'center', + }), + { + selectors: { + [`&${isBottom}`]: { + width: toolbarItemSize, + }, + }, + }, +]); + +export const toggleEditorButton = style([ + sprinkles({ + position: 'relative', + borderRadius: 'large', + padding: 'none', + cursor: 'pointer', + width: 'full', + appearance: 'none', + border: 0, + }), + { + background: 'transparent', + WebkitTapHighlightColor: 'transparent', + outline: 'none', + minWidth: vars.touchableSize, + height: vars.touchableSize, + selectors: { + [`&:not(:hover):not(:focus)`]: { + opacity: 0.3, + }, + [`&:hover::before, &:focus::before`]: { + opacity: 0.05, + }, + }, + '::before': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + backgroundColor: 'currentColor', + opacity: 0, + pointerEvents: 'none', + borderRadius: vars.radii.large, + transition: vars.transition.slow, + }, + }, +]); + +export const editorContainer = style([ + sprinkles({ + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + }), + { + right: toolbarItemSize, + }, +]); + +export const toolbarContainer = sprinkles({ + position: 'absolute', + top: 0, + bottom: 0, + right: 0, +}); diff --git a/src/Playroom/Playroom.less b/src/Playroom/Playroom.less deleted file mode 100644 index 537e21b2..00000000 --- a/src/Playroom/Playroom.less +++ /dev/null @@ -1,117 +0,0 @@ -@import (reference) './variables.less'; - -:global(html) { - width: 100%; - height: 100%; - overflow: hidden; - background-color: @body; -} - -:global(body) { - margin: 0; -} - -.root { - height: 100vh; - width: 100vw; -} - -.previewContainer { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; -} - -.resizeableContainer { - position: absolute !important; // override internal inline style - bottom: 0; - right: 0; - overflow: hidden; - box-shadow: @shadow-small; - transition: @transition-slow; -} - -.resizeableContainer_isRight { - top: 0; - max-width: 90vw; - - &.resizeableContainer_isHidden { - transform: translateX(100%); - } -} - -.resizeableContainer_isBottom { - left: 0; - max-height: 90vh; - - &.resizeableContainer_isHidden { - transform: translateY(100%); - } -} - -.toggleEditorContainer { - position: absolute; - bottom: 0; - right: 0; - display: flex; - justify-content: center; - - &.isBottom { - width: @toolbar-item-size; - } -} - -.toggleEditorButton { - position: relative; - appearance: none; - background: transparent; - -webkit-tap-highlight-color: transparent; - outline: none; - border: 0; - padding: 0; - border-radius: @radius-large; - min-width: @interaction-height; - width: 100%; - height: @interaction-height; - cursor: pointer; - - &:not(:hover):not(:focus) { - opacity: @preview-inactive-label-opacity; - } - - &:before { - content: ''; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - background-color: currentColor; - border-radius: @radius-large; - opacity: 0; - transition: @transition-slow; - pointer-events: none; - - :hover&, - :focus& { - opacity: 0.05; - } - } -} - -.editorContainer { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: @toolbar-closed-size; -} - -.toolbarContainer { - position: absolute; - right: 0; - top: 0; - bottom: 0; -} diff --git a/src/Playroom/Playroom.tsx b/src/Playroom/Playroom.tsx index b8ad0a3a..54044331 100644 --- a/src/Playroom/Playroom.tsx +++ b/src/Playroom/Playroom.tsx @@ -6,43 +6,20 @@ import Frames from './Frames/Frames'; import WindowPortal from './WindowPortal'; import { Snippets } from '../../utils'; import componentsToHints from '../utils/componentsToHints'; -import Toolbar from './Toolbar/Toolbar'; +import Toolbar, { toolbarItemCount } from './Toolbar/Toolbar'; import ChevronIcon from './icons/ChevronIcon'; import { StatusMessage } from './StatusMessage/StatusMessage'; import { StoreContext, EditorPosition } from '../StoreContext/StoreContext'; -// @ts-ignore -import themeVars from '!!less-vars-loader?resolveVariables!./variables.less'; - -const getThemeVariable = (name: string) => { - const resolvedVar = themeVars[name]; - - if (!resolvedVar) { - throw new Error(`Cannot resolve "${name}" from variables`); - } - - if (!(typeof resolvedVar === 'string' && /(px|[0-9])$/.test(resolvedVar))) { - throw new Error( - `Invalid characters "${resolvedVar}", must be a number of pixel value` - ); - } - - return parseInt(resolvedVar.replace(/px$/, ''), 10); -}; - -const MIN_HEIGHT = - getThemeVariable('toolbar-item-size') * - getThemeVariable('toolbar-max-item-count'); -const MIN_WIDTH = - getThemeVariable('toolbar-open-size') + - getThemeVariable('toolbar-closed-size') + - 80; +const MIN_HEIGHT = toolbarItemSize * toolbarItemCount; +const MIN_WIDTH = toolbarOpenSize + toolbarItemSize + 80; // @ts-ignore import { CodeEditor } from './CodeEditor/CodeEditor'; -// @ts-ignore -import styles from './Playroom.less'; +import * as styles from './Playroom.css'; +import { toolbarOpenSize } from './Toolbar/Toolbar.css'; +import { toolbarItemSize } from './ToolbarItem/ToolbarItem.css'; const resizableConfig = (position: EditorPosition = 'bottom') => ({ top: position === 'bottom', diff --git a/src/Playroom/Preview.css.ts b/src/Playroom/Preview.css.ts new file mode 100644 index 00000000..822e7cc9 --- /dev/null +++ b/src/Playroom/Preview.css.ts @@ -0,0 +1,11 @@ +import { sprinkles } from './sprinkles.css'; + +export const renderContainer = sprinkles({ + position: 'relative', + zIndex: 0, +}); + +export const splashScreenContainer = sprinkles({ + position: 'relative', + zIndex: 1, +}); diff --git a/src/Playroom/Preview.less b/src/Playroom/Preview.less deleted file mode 100644 index 067c0a4f..00000000 --- a/src/Playroom/Preview.less +++ /dev/null @@ -1,9 +0,0 @@ -.renderContainer { - position: relative; - z-index: 0; -} - -.splashScreenContainer { - position: relative; - z-index: 1; -} diff --git a/src/Playroom/Preview.tsx b/src/Playroom/Preview.tsx index 9cf54eef..0183aafe 100644 --- a/src/Playroom/Preview.tsx +++ b/src/Playroom/Preview.tsx @@ -5,8 +5,7 @@ import { useParams } from '../utils/params'; import { compileJsx } from '../utils/compileJsx'; import SplashScreen from './SplashScreen/SplashScreen'; -// @ts-ignore -import styles from './Preview.less'; +import * as styles from './Preview.css'; // @ts-ignore import CatchErrors from './CatchErrors/CatchErrors'; diff --git a/src/Playroom/PreviewPanel/ThemeSelector.css.ts b/src/Playroom/PreviewPanel/ThemeSelector.css.ts new file mode 100644 index 00000000..2dd04806 --- /dev/null +++ b/src/Playroom/PreviewPanel/ThemeSelector.css.ts @@ -0,0 +1,62 @@ +import { style } from '@vanilla-extract/css'; +import { sprinkles } from '../sprinkles.css'; + +export const root = sprinkles({ + position: 'relative', +}); + +export const label = sprinkles({ + userSelect: 'none', + pointerEvents: 'none', +}); + +export const row = sprinkles({ + display: 'flex', + alignItems: 'center', +}); + +export const column = style([ + sprinkles({ + display: 'block', + }), + { + minWidth: 0, + }, +]); + +export const minColumn = style({ + flexShrink: 0, +}); + +export const select = style([ + sprinkles({ + position: 'absolute', + inset: 0, + width: 'full', + opacity: 0, + font: 'standard', + }), + {}, +]); + +export const focusOverlay = style([ + sprinkles({ + position: 'absolute', + pointerEvents: 'none', + borderRadius: 'large', + opacity: 0, + transition: 'medium', + boxShadow: 'focus', + }), + { + top: '-4px', + left: '-4px', + right: '-4px', + bottom: '-4px', + selectors: { + [`${select}:focus:not(:hover) ~ &`]: { + opacity: 1, + }, + }, + }, +]); diff --git a/src/Playroom/PreviewPanel/ThemeSelector.less b/src/Playroom/PreviewPanel/ThemeSelector.less deleted file mode 100644 index bdb93643..00000000 --- a/src/Playroom/PreviewPanel/ThemeSelector.less +++ /dev/null @@ -1,54 +0,0 @@ -@import (reference) '../variables.less'; - -.root { - position: relative; -} - -.label { - user-select: none; - pointer-events: none; -} - -.row { - display: flex; - align-items: center; -} - -.column { - display: block; - min-width: 0; -} - -.minColumn { - flex-shrink: 0; -} - -.focusOverlay { - position: absolute; - pointer-events: none; - top: -4px; - left: -4px; - right: -4px; - bottom: -4px; - box-shadow: @focus-outline; - border-radius: @radius-large; - opacity: 0; - transition: @transition-medium; -} - -.select { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - width: 100%; - opacity: 0; - font: @text-standard; - - &:focus:not(:hover) { - ~ .focusOverlay { - opacity: 1; - } - } -} diff --git a/src/Playroom/PreviewPanel/ThemeSelector.tsx b/src/Playroom/PreviewPanel/ThemeSelector.tsx index a739dd48..ca6299a3 100644 --- a/src/Playroom/PreviewPanel/ThemeSelector.tsx +++ b/src/Playroom/PreviewPanel/ThemeSelector.tsx @@ -4,8 +4,7 @@ import classnames from 'classnames'; import ChevronIcon from '../icons/ChevronIcon'; import { Text } from '../Text/Text'; -// @ts-ignore -import styles from './ThemeSelector.less'; +import * as styles from './ThemeSelector.css'; interface ThemeSelectorProps { themes: string[]; diff --git a/src/Playroom/SettingsPanel/SettingsPanel.css.ts b/src/Playroom/SettingsPanel/SettingsPanel.css.ts new file mode 100644 index 00000000..ea7002ae --- /dev/null +++ b/src/Playroom/SettingsPanel/SettingsPanel.css.ts @@ -0,0 +1,71 @@ +import { colorPaletteVars, sprinkles, vars } from '../sprinkles.css'; +import { style } from '@vanilla-extract/css'; + +export const fieldset = sprinkles({ + border: 0, + margin: 'none', + padding: 'none', +}); + +export const radioContainer = sprinkles({ + display: 'flex', + paddingTop: 'medium', +}); + +export const realRadio = style([ + sprinkles({ + position: 'absolute', + opacity: 0, + pointerEvents: 'none', + }), + { + height: vars.touchableSize, + width: vars.touchableSize, + }, +]); + +export const labelText = sprinkles({ + display: 'block', + position: 'relative', + zIndex: 1, +}); + +export const label = style([ + sprinkles({ + position: 'relative', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + cursor: 'pointer', + marginRight: 'xxsmall', + }), + { + height: vars.touchableSize, + width: vars.touchableSize, + '::before': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + backgroundColor: colorPaletteVars.background.selection, + borderRadius: vars.radii.large, + transition: vars.transition.medium, + opacity: 0, + transform: 'scale(0.8)', + }, + selectors: { + [[ + `${realRadio}:checked ~ &`, + `html:not([data-playroom-dark]) ${realRadio}:hover ~ &`, + ].join(',')]: { + color: colorPaletteVars.foreground.accent, + }, + [`${realRadio}:focus ~ &::before, ${realRadio}:hover ~ &::before`]: { + opacity: 1, + transform: 'scale(1)', + }, + }, + }, +]); diff --git a/src/Playroom/SettingsPanel/SettingsPanel.tsx b/src/Playroom/SettingsPanel/SettingsPanel.tsx new file mode 100644 index 00000000..47a111e4 --- /dev/null +++ b/src/Playroom/SettingsPanel/SettingsPanel.tsx @@ -0,0 +1,117 @@ +import React, { useContext, ReactChild } from 'react'; +import { Heading } from '../Heading/Heading'; +import { ToolbarPanel } from '../ToolbarPanel/ToolbarPanel'; +import { + ColorScheme, + EditorPosition, + StoreContext, +} from '../../StoreContext/StoreContext'; +import { Stack } from '../Stack/Stack'; +import EditorRightIcon from '../icons/EditorRightIcon'; +import EditorBottomIcon from '../icons/EditorBottomIcon'; +import EditorUndockedIcon from '../icons/EditorUndockedIcon'; + +import * as styles from './SettingsPanel.css'; +import ColorModeSystemIcon from '../icons/ColorModeSystemIcon'; +import ColorModeLightIcon from '../icons/ColorModeLightIcon'; +import ColorModeDarkIcon from '../icons/ColorModeDarkIcon'; + +const positionIcon: Record = { + undocked: , + right: , + bottom: , +}; + +const colorModeIcon: Record = { + light: , + dark: , + system: , +}; + +interface SettingsPanelProps {} + +export default ({}: SettingsPanelProps) => { + const [{ editorPosition, colorScheme }, dispatch] = useContext(StoreContext); + + return ( + + +
+ + Editor Position + +
+ {['Bottom', 'Right'].map((option) => ( +
+ + dispatch({ + type: 'updateEditorPosition', + payload: { + position: option.toLowerCase() as EditorPosition, + }, + }) + } + className={styles.realRadio} + /> + +
+ ))} +
+
+ +
+ + Color Scheme + +
+ {['Light', 'Dark', 'System'].map((option) => ( +
+ + dispatch({ + type: 'updateColorScheme', + payload: { + colorScheme: option.toLowerCase() as ColorScheme, + }, + }) + } + className={styles.realRadio} + /> + +
+ ))} +
+
+
+
+ ); +}; diff --git a/src/Playroom/Snippets/SearchField/SearchField.css.ts b/src/Playroom/Snippets/SearchField/SearchField.css.ts new file mode 100644 index 00000000..5e867a35 --- /dev/null +++ b/src/Playroom/Snippets/SearchField/SearchField.css.ts @@ -0,0 +1,22 @@ +import { sprinkles, vars, colorPaletteVars } from '../../sprinkles.css'; +import { style } from '@vanilla-extract/css'; + +export const field = style([ + sprinkles({ + font: 'large', + border: 0, + width: 'full', + paddingX: 'xlarge', + }), + { + color: colorPaletteVars.foreground.neutral, + height: vars.touchableSize, + background: colorPaletteVars.background.surface, + ':focus': { + outline: 'none', + }, + '::placeholder': { + color: colorPaletteVars.foreground.neutralSoft, + }, + }, +]); diff --git a/src/Playroom/Snippets/SearchField/SearchField.less b/src/Playroom/Snippets/SearchField/SearchField.less deleted file mode 100644 index bfefde66..00000000 --- a/src/Playroom/Snippets/SearchField/SearchField.less +++ /dev/null @@ -1,18 +0,0 @@ -@import (reference) '../../variables.less'; - -.field { - font: @text-large; - border: none; - width: 100%; - padding: 0 @field-gutter; - height: @interaction-height; - background: @white; - - &:focus { - outline: none; - } - - &::placeholder { - color: @gray-3; - } -} diff --git a/src/Playroom/Snippets/SearchField/SearchField.tsx b/src/Playroom/Snippets/SearchField/SearchField.tsx index a50cc3c4..10c0f2fc 100644 --- a/src/Playroom/Snippets/SearchField/SearchField.tsx +++ b/src/Playroom/Snippets/SearchField/SearchField.tsx @@ -1,7 +1,6 @@ import React, { AllHTMLAttributes } from 'react'; -// @ts-ignore -import styles from './SearchField.less'; +import * as styles from './SearchField.css'; type InputProps = AllHTMLAttributes; interface Props { diff --git a/src/Playroom/Snippets/Snippets.css.ts b/src/Playroom/Snippets/Snippets.css.ts new file mode 100644 index 00000000..65fb4921 --- /dev/null +++ b/src/Playroom/Snippets/Snippets.css.ts @@ -0,0 +1,82 @@ +import { style } from '@vanilla-extract/css'; +import { toolbarItemSize } from '../ToolbarItem/ToolbarItem.css'; +import { sprinkles, vars, colorPaletteVars } from '../sprinkles.css'; + +export const root = sprinkles({ + position: 'relative', + overflow: 'hidden', + height: 'full', +}); + +export const fieldContainer = style([ + sprinkles({ + position: 'absolute', + top: 0, + left: 0, + right: 0, + display: 'flex', + alignItems: 'center', + paddingX: 'medium', + }), + { + height: toolbarItemSize, + boxShadow: `inset 0 -1px 0 0 ${colorPaletteVars.border.standard}`, + }, +]); + +export const snippetsContainer = style([ + sprinkles({ + position: 'absolute', + left: 0, + bottom: 0, + right: 0, + overflow: 'auto', + padding: 'none', + margin: 'medium', + }), + { + top: toolbarItemSize, + }, +]); + +export const snippet = style([ + sprinkles({ + position: 'relative', + cursor: 'pointer', + paddingY: 'large', + paddingX: 'xlarge', + }), + { + color: colorPaletteVars.foreground.neutral, + backgroundColor: colorPaletteVars.background.surface, + '::before': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + backgroundColor: colorPaletteVars.background.selection, + borderRadius: vars.radii.medium, + opacity: 0, + transition: vars.transition.slow, + pointerEvents: 'none', + }, + }, +]); + +export const snippetName = style([ + sprinkles({ + display: 'block', + }), + { + color: colorPaletteVars.foreground.secondary, + }, +]); + +export const highlight = style({ + color: colorPaletteVars.foreground.accent, + '::before': { + opacity: 1, + }, +}); diff --git a/src/Playroom/Snippets/Snippets.less b/src/Playroom/Snippets/Snippets.less deleted file mode 100644 index 179b19f7..00000000 --- a/src/Playroom/Snippets/Snippets.less +++ /dev/null @@ -1,65 +0,0 @@ -@import (reference) '../variables.less'; - -.root { - position: relative; - overflow: hidden; - height: 100%; -} - -.fieldContainer { - position: absolute; - top: 0; - left: 0; - right: 0; - height: @toolbar-item-size; - display: flex; - align-items: center; - padding: 0 @snippet-gutter; - box-shadow: inset 0 -@toolbar-border-thickness 0 0 @toolbar-border-color; -} - -.snippetsContainer { - position: absolute; - top: @toolbar-item-size; - left: 0; - bottom: 0; - right: 0; - overflow: auto; - margin: @snippet-gutter; - padding: 0; -} - -.snippet { - position: relative; - padding: 10px @field-gutter; - cursor: pointer; - color: @snippet-foreground; - background-color: @snippet-background; - - &:before { - content: ''; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - background-color: @snippet-selection; - border-radius: @radius-medium; - opacity: 0; - transition: @transition-slow; - pointer-events: none; - } -} - -.snippetName { - display: block; - opacity: 0.7; -} - -.highlight { - color: @snippet-highlight; - - &:before { - opacity: 1; - } -} diff --git a/src/Playroom/Snippets/Snippets.tsx b/src/Playroom/Snippets/Snippets.tsx index 750393d4..339a72cb 100644 --- a/src/Playroom/Snippets/Snippets.tsx +++ b/src/Playroom/Snippets/Snippets.tsx @@ -8,8 +8,7 @@ import SearchField from './SearchField/SearchField'; import { Strong } from '../Strong/Strong'; import { Text } from '../Text/Text'; -// @ts-ignore -import styles from './Snippets.less'; +import * as styles from './Snippets.css'; type HighlightIndex = number | null; type ReturnedSnippet = Snippet | null; @@ -185,10 +184,12 @@ export default ({ snippets, onHighlight, onClose }: Props) => { onMouseDown={() => closeHandler(filteredSnippets[index])} title={getLabel(snippet)} > - - {snippet.group} - {snippet.name} - + + + {snippet.group} + {snippet.name} + + ); })} diff --git a/src/Playroom/SplashScreen/SplashScreen.css.ts b/src/Playroom/SplashScreen/SplashScreen.css.ts new file mode 100644 index 00000000..8a881e17 --- /dev/null +++ b/src/Playroom/SplashScreen/SplashScreen.css.ts @@ -0,0 +1,58 @@ +import { style, globalStyle, keyframes } from '@vanilla-extract/css'; +import { sprinkles, colorPaletteVars } from '../sprinkles.css'; + +export const animationDuration = 1300; +export const animationDelay = 500; +export const animationIterationCount = 2; + +export const root = style([ + sprinkles({ + position: 'fixed', + inset: 0, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + textAlign: 'center', + transition: 'slow', + }), + { + zIndex: 100, + background: colorPaletteVars.background.neutral, + color: colorPaletteVars.foreground.neutralInverted, + }, +]); + +export const hideSplash = sprinkles({ + opacity: 0, + pointerEvents: 'none', +}); + +export const trace = style({}); +const traceKeyframes = keyframes({ + '0%, 100%': { + opacity: 0, + }, + '20%, 80%': { + opacity: 1, + }, + '50%, 100%': { + strokeDashoffset: 0, + }, +}); +globalStyle(`${trace} > svg > path`, { + strokeDasharray: 1000, + strokeDashoffset: 1000, + animationName: traceKeyframes, + animationDuration: `${animationDuration}ms`, + animationDelay: `${animationDelay}ms`, + animationDirection: 'forwards', + animationTimingFunction: 'ease-in', + animationIterationCount, + animationFillMode: 'forwards', +}); + +export const size = style({ + margin: '0 auto', + width: '40vw', + maxWidth: '200px', +}); diff --git a/src/Playroom/SplashScreen/SplashScreen.less b/src/Playroom/SplashScreen/SplashScreen.less deleted file mode 100644 index 7a94f82a..00000000 --- a/src/Playroom/SplashScreen/SplashScreen.less +++ /dev/null @@ -1,60 +0,0 @@ -@import (reference) '../variables.less'; - -@animationDuration: 1300; -@animationDelay: 500; -@animationIterationCount: 2; - -.root { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 100; - display: flex; - align-items: center; - justify-content: center; - text-align: center; - background: @gray-6; - color: @white; - transition: @transition-speed-slow; -} - -.hideSplash { - opacity: 0; - pointer-events: none; -} - -.trace > svg > path { - @dash-size: 1000; - @keyframes trace { - 0%, - 100% { - opacity: 0; - } - 20%, - 80% { - opacity: 1; - } - 50%, - 100% { - stroke-dashoffset: 0; - } - } - - stroke-dasharray: @dash-size; - stroke-dashoffset: @dash-size; - animation-name: trace; - animation-duration: unit(@animationDuration, ms); - animation-delay: unit(@animationDelay, ms); - animation-direction: forwards; - animation-timing-function: ease-in; - animation-iteration-count: @animationIterationCount; - animation-fill-mode: forwards; -} - -.size { - margin: 0 auto; - width: 40vw; - max-width: 200px; -} diff --git a/src/Playroom/SplashScreen/SplashScreen.tsx b/src/Playroom/SplashScreen/SplashScreen.tsx index 8378eb29..1d78dc4a 100644 --- a/src/Playroom/SplashScreen/SplashScreen.tsx +++ b/src/Playroom/SplashScreen/SplashScreen.tsx @@ -2,15 +2,14 @@ import React, { useState, useEffect } from 'react'; import classnames from 'classnames'; import { Logo } from '../Logo/Logo'; -import { +import * as stylesheet from './SplashScreen.css'; + +const { animationDuration, animationDelay, animationIterationCount, - // @ts-ignore -} from '!!less-vars-loader!./SplashScreen.less'; - -// @ts-ignore -import styles from './SplashScreen.less'; + ...styles +} = stylesheet; export default () => { const [hide, setHide] = useState(false); @@ -18,8 +17,7 @@ export default () => { useEffect(() => { const hideSplash = setTimeout( () => setHide(true), - parseInt(animationDelay, 10) + - parseInt(animationDuration, 10) * parseInt(animationIterationCount, 10) + animationDelay + animationDuration * animationIterationCount ); return () => clearTimeout(hideSplash); diff --git a/src/Playroom/Stack/Stack.css.ts b/src/Playroom/Stack/Stack.css.ts new file mode 100644 index 00000000..7ad2ca10 --- /dev/null +++ b/src/Playroom/Stack/Stack.css.ts @@ -0,0 +1,49 @@ +import { calc } from '@vanilla-extract/css-utils'; +import { style, createVar } from '@vanilla-extract/css'; +import { vars } from '../sprinkles.css'; + +const size = createVar(); + +export const gap = style({ + selectors: { + ['&:not(:last-child)']: { + paddingBottom: size, + }, + }, +}); + +export const xxsmall = style({ + vars: { + [size]: vars.grid, + }, +}); + +export const xsmall = style({ + vars: { + [size]: calc(vars.grid).multiply(2).toString(), + }, +}); + +export const small = style({ + vars: { + [size]: calc(vars.grid).multiply(3).toString(), + }, +}); + +export const medium = style({ + vars: { + [size]: calc(vars.grid).multiply(4).toString(), + }, +}); + +export const large = style({ + vars: { + [size]: calc(vars.grid).multiply(6).toString(), + }, +}); + +export const xlarge = style({ + vars: { + [size]: calc(vars.grid).multiply(12).toString(), + }, +}); diff --git a/src/Playroom/Stack/Stack.less b/src/Playroom/Stack/Stack.less deleted file mode 100644 index a973c35e..00000000 --- a/src/Playroom/Stack/Stack.less +++ /dev/null @@ -1,23 +0,0 @@ -@import (reference) '../variables.less'; - -.stackItem:not(:last-child), -.divider { - &.xxsmall { - padding-bottom: @grid; - } - &.xsmall { - padding-bottom: @grid * 2; - } - &.small { - padding-bottom: @grid * 3; - } - &.medium { - padding-bottom: @grid * 4; - } - &.large { - padding-bottom: @grid * 6; - } - &.xlarge { - padding-bottom: @grid * 12; - } -} diff --git a/src/Playroom/Stack/Stack.tsx b/src/Playroom/Stack/Stack.tsx index 187c0737..0437433d 100644 --- a/src/Playroom/Stack/Stack.tsx +++ b/src/Playroom/Stack/Stack.tsx @@ -3,8 +3,7 @@ import classnames from 'classnames'; import { Divider } from '../Divider/Divider'; -// @ts-ignore -import styles from './Stack.less'; +import * as styles from './Stack.css'; interface ReactNodeArray extends Array {} type ReactNodeNoStrings = @@ -27,33 +26,20 @@ interface Props { dividers?: boolean; } -export const Stack = ({ children, space, dividers = false }: Props) => { - const stackItems = Children.toArray(children); - - const stackItemSizeClass = classnames({ - [styles.xxsmall]: space === 'xxsmall', - [styles.xsmall]: space === 'xsmall', - [styles.small]: space === 'small', - [styles.medium]: space === 'medium', - [styles.large]: space === 'large', - [styles.xlarge]: space === 'xlarge', - }); - - return ( -
- {stackItems.map((item, index) => ( -
- {dividers && index > 0 ? ( -
- -
- ) : null} - {item} -
- ))} -
- ); -}; +export const Stack = ({ children, space, dividers = false }: Props) => ( +
+ {Children.toArray(children).map((item, index) => ( +
+ {dividers && index > 0 ? ( +
+ +
+ ) : null} + {item} +
+ ))} +
+); diff --git a/src/Playroom/StatusMessage/StatusMessage.css.ts b/src/Playroom/StatusMessage/StatusMessage.css.ts new file mode 100644 index 00000000..f1a2301b --- /dev/null +++ b/src/Playroom/StatusMessage/StatusMessage.css.ts @@ -0,0 +1,72 @@ +import { calc } from '@vanilla-extract/css-utils'; +import { style } from '@vanilla-extract/css'; +import { sprinkles, vars, colorPaletteVars } from '../sprinkles.css'; +import { toolbarItemSize } from '../ToolbarItem/ToolbarItem.css'; + +const statusGutter = '15px'; +const icon = '16px'; + +export const dismissable = style({}); +export const show = style({}); +export const positive = style({}); +export const critical = style({}); + +const offset = '50%'; +export const status = style([ + sprinkles({ + position: 'absolute', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + whiteSpace: 'nowrap', + transition: 'fast', + borderRadius: 'large', + }), + { + padding: `0 ${statusGutter}`, + left: offset, + transform: `translateX(-${offset})`, + top: calc(vars.grid).multiply(5).toString(), + height: calc(vars.grid).multiply(8).toString(), + maxWidth: calc('100vw') + .subtract(`${toolbarItemSize}px`) + .subtract(calc(vars.codeGutterSize).multiply(2)) + .toString(), + selectors: { + [`&${dismissable}`]: { + paddingRight: calc(statusGutter).multiply(2).add(icon).toString(), + }, + [`&:not(${show})`]: { + opacity: 0, + pointerEvents: 'none', + transform: `translate3d(-${offset}, -10px, 0)`, + }, + [`&${positive}`]: { + backgroundColor: colorPaletteVars.background.positive, + }, + [`&${critical}`]: { + backgroundColor: colorPaletteVars.background.critical, + }, + }, + }, +]); + +export const dismiss = style([ + sprinkles({ + display: 'flex', + position: 'absolute', + cursor: 'pointer', + transition: 'fast', + }), + { + paddingLeft: statusGutter, + right: statusGutter, + height: icon, + width: icon, + selectors: { + [`&:not(:hover)`]: { + opacity: 0.4, + }, + }, + }, +]); diff --git a/src/Playroom/StatusMessage/StatusMessage.less b/src/Playroom/StatusMessage/StatusMessage.less deleted file mode 100644 index 01e0b1f0..00000000 --- a/src/Playroom/StatusMessage/StatusMessage.less +++ /dev/null @@ -1,53 +0,0 @@ -@import (reference) '../variables.less'; - -@gutter: 15px; -@icon: 16px; - -.status { - @offset: 50%; - position: absolute; - left: @offset; - transform: translateX(-@offset); - top: @grid * 5; - height: @grid * 8; - border-radius: @radius-large; - padding: 0 @gutter; - display: flex; - align-items: center; - justify-content: center; - white-space: nowrap; - transition: @transition-fast; - max-width: calc(100vw - @toolbar-item-size - (@code-gutter-size * 2)); - - &.dismissable { - padding-right: (@gutter * 2 + @icon); - } - - &:not(.show) { - opacity: 0; - pointer-events: none; - transform: translate3d(-@offset, -10px, 0); - } - - &.positive { - background-color: @positive-light; - } - &.critical { - background-color: @critical-light; - } -} - -.dismiss { - display: flex; - position: absolute; - right: @gutter; - height: @icon; - width: @icon; - padding-left: @gutter; - cursor: pointer; - transition: @transition-fast; - - &:not(:hover) { - opacity: 0.4; - } -} diff --git a/src/Playroom/StatusMessage/StatusMessage.tsx b/src/Playroom/StatusMessage/StatusMessage.tsx index aeee4114..3d9f14cd 100644 --- a/src/Playroom/StatusMessage/StatusMessage.tsx +++ b/src/Playroom/StatusMessage/StatusMessage.tsx @@ -10,8 +10,7 @@ import { StoreContext } from '../../StoreContext/StoreContext'; import { Text } from '../Text/Text'; import DismissIcon from '../icons/DismissIcon'; -// @ts-ignore -import styles from './StatusMessage.less'; +import * as styles from './StatusMessage.css'; const exitAnimationDuration = 300; const statusMessageDuration = 3000; @@ -65,7 +64,7 @@ export const StatusMessage = ({ dismissable = false }: Props) => { [styles.positive]: tone === 'positive', [styles.critical]: tone === 'critical', [styles.dismissable]: dismissable, - [styles.show]: show, // eslint-disable-line css-modules/no-undef-class + [styles.show]: show, })} > {message} diff --git a/src/Playroom/Strong/Strong.css.ts b/src/Playroom/Strong/Strong.css.ts new file mode 100644 index 00000000..29f9e4e0 --- /dev/null +++ b/src/Playroom/Strong/Strong.css.ts @@ -0,0 +1,6 @@ +import { sprinkles } from '../sprinkles.css'; + +export const strong = sprinkles({ + display: 'inline', + fontWeight: 'strong', +}); diff --git a/src/Playroom/Strong/Strong.less b/src/Playroom/Strong/Strong.less deleted file mode 100644 index 59893af8..00000000 --- a/src/Playroom/Strong/Strong.less +++ /dev/null @@ -1,6 +0,0 @@ -@import (reference) '../variables.less'; - -.strong { - display: inline; - font-weight: @bold; -} diff --git a/src/Playroom/Strong/Strong.tsx b/src/Playroom/Strong/Strong.tsx index 2abed5e9..5db82849 100644 --- a/src/Playroom/Strong/Strong.tsx +++ b/src/Playroom/Strong/Strong.tsx @@ -1,7 +1,6 @@ import React, { ReactNode } from 'react'; -// @ts-ignore -import styles from './Strong.less'; +import * as styles from './Strong.css'; interface Props { children: ReactNode; diff --git a/src/Playroom/Text/Text.css.ts b/src/Playroom/Text/Text.css.ts new file mode 100644 index 00000000..81cf1271 --- /dev/null +++ b/src/Playroom/Text/Text.css.ts @@ -0,0 +1,44 @@ +import { style } from '@vanilla-extract/css'; +import { sprinkles, colorPaletteVars } from '../sprinkles.css'; + +export const base = sprinkles({ + display: 'block', +}); + +export const neutral = style({ + color: colorPaletteVars.foreground.neutral, +}); + +export const critical = style({ + color: colorPaletteVars.foreground.critical, +}); + +export const xsmall = sprinkles({ + font: 'xsmall', +}); + +export const small = sprinkles({ + font: 'small', +}); + +export const standard = sprinkles({ + font: 'standard', +}); + +export const large = sprinkles({ + font: 'large', +}); + +export const strong = sprinkles({ + fontWeight: 'strong', +}); + +export const truncate = style([ + sprinkles({ + whiteSpace: 'nowrap', + overflow: 'hidden', + }), + { + textOverflow: 'ellipsis', + }, +]); diff --git a/src/Playroom/Text/Text.less b/src/Playroom/Text/Text.less deleted file mode 100644 index 9f7198b7..00000000 --- a/src/Playroom/Text/Text.less +++ /dev/null @@ -1,36 +0,0 @@ -@import (reference) '../variables.less'; - -.base { - display: block; -} - -.neutral { - color: @text-neutral; -} - -.critical { - color: @critical; -} - -.xsmall { - font: @text-xsmall; -} -.small { - font: @text-small; -} -.standard { - font: @text-standard; -} -.large { - font: @text-large; -} - -.strong { - font-weight: @bold; -} - -.truncate { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} diff --git a/src/Playroom/Text/Text.tsx b/src/Playroom/Text/Text.tsx index e5ac154f..94a3e973 100644 --- a/src/Playroom/Text/Text.tsx +++ b/src/Playroom/Text/Text.tsx @@ -1,8 +1,7 @@ import React, { ElementType, ReactNode } from 'react'; import classnames from 'classnames'; -// @ts-ignore -import styles from './Text.less'; +import * as styles from './Text.css'; interface Props { size?: 'xsmall' | 'small' | 'standard' | 'large'; @@ -24,14 +23,8 @@ export const Text = ({ React.createElement( component, { - className: classnames(styles.base, { - [styles.xsmall]: size === 'xsmall', - [styles.small]: size === 'small', - [styles.standard]: size === 'standard', - [styles.large]: size === 'large', + className: classnames(styles.base, styles[size], styles[tone], { [styles.strong]: weight === 'strong', - [styles.critical]: tone === 'critical', - [styles.neutral]: tone === 'neutral', [styles.truncate]: truncate, }), }, diff --git a/src/Playroom/Toolbar/Toolbar.css.ts b/src/Playroom/Toolbar/Toolbar.css.ts new file mode 100644 index 00000000..d0fd29b9 --- /dev/null +++ b/src/Playroom/Toolbar/Toolbar.css.ts @@ -0,0 +1,115 @@ +import { calc } from '@vanilla-extract/css-utils'; +import { style } from '@vanilla-extract/css'; +import { sprinkles, colorPaletteVars } from '../sprinkles.css'; +import { toolbarItemSize } from '../ToolbarItem/ToolbarItem.css'; + +export const toolbarOpenSize = 300; +const toolbarBorderThickness = '1px'; + +export const isOpen = style({}); +export const root = style([ + sprinkles({ + position: 'relative', + height: 'full', + display: 'flex', + flexDirection: 'row-reverse', + }), + { + color: colorPaletteVars.foreground.neutral, + minWidth: calc(`${toolbarItemSize}px`) + .add(toolbarBorderThickness) + .toString(), + selectors: { + [`&${isOpen}`]: { + width: '100vw', + }, + }, + }, +]); + +export const backdrop = sprinkles({ + position: 'absolute', + height: 'viewport', + width: 'viewport', +}); + +export const sidebar = sprinkles({ + position: 'absolute', + display: 'flex', + pointerEvents: 'none', + height: 'full', + flexDirection: 'row-reverse', + overflow: 'hidden', +}); + +export const topButtons = sprinkles({ + transition: 'medium', +}); + +export const positions_isOpen = style({}); +export const positionContainer = style([ + sprinkles({ + position: 'absolute', + top: 0, + width: 'full', + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-end', + justifyContent: 'flex-end', + transition: 'medium', + }), + { + bottom: toolbarItemSize, + selectors: { + [`&:not(${positions_isOpen})`]: { + opacity: 0, + pointerEvents: 'none', + transform: 'translateY(20px)', + }, + }, + }, +]); + +export const buttons = style([ + sprinkles({ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + pointerEvents: 'auto', + justifyContent: 'space-between', + position: 'relative', + zIndex: 1, + }), + { + width: toolbarItemSize, + backgroundColor: colorPaletteVars.background.surface, + borderLeft: `${toolbarBorderThickness} solid ${colorPaletteVars.border.standard}`, + }, +]); + +export const panel = style([ + sprinkles({ + position: 'relative', + display: 'flex', + overflow: 'auto', + transition: 'slow', + pointerEvents: 'auto', + }), + { + width: toolbarOpenSize, + backgroundColor: colorPaletteVars.background.surface, + borderLeft: `${toolbarBorderThickness} solid ${colorPaletteVars.border.standard}`, + selectors: { + [`${root}:not(${isOpen}) &`]: { + transform: `translateX(${calc(`${toolbarOpenSize}px`).multiply(0.3)})`, + opacity: 0, + pointerEvents: 'none', + }, + }, + }, +]); + +export const preference = sprinkles({ + position: 'absolute', + inset: 0, +}); diff --git a/src/Playroom/Toolbar/Toolbar.less b/src/Playroom/Toolbar/Toolbar.less deleted file mode 100644 index 95cd0557..00000000 --- a/src/Playroom/Toolbar/Toolbar.less +++ /dev/null @@ -1,94 +0,0 @@ -@import (reference) '../variables.less'; - -.root { - position: relative; - height: 100%; - min-width: @toolbar-closed-size + @toolbar-border-thickness; - display: flex; - flex-direction: row-reverse; - color: @toolbar-foregound; - - &.isOpen { - width: 100vw; - } -} - -.backdrop { - position: absolute; - height: 100vh; - width: 100vw; -} - -.sidebar { - position: absolute; - display: flex; - pointer-events: none; - height: 100%; - flex-direction: row-reverse; - overflow: hidden; -} - -.topButtons { - transition: @transition-medium; -} - -.topButtons_hide { - opacity: 0.2; - pointer-events: none; -} - -.positionContainer { - position: absolute; - bottom: @toolbar-closed-size; - top: 0; - width: 100%; - display: flex; - flex-direction: column; - align-items: flex-end; - justify-content: flex-end; - transition: @transition-medium; - - &:not(.positions_isOpen) { - opacity: 0; - pointer-events: none; - transform: translateY(20px); - } -} - -.buttons { - display: flex; - flex-direction: column; - align-items: center; - width: @toolbar-closed-size; - pointer-events: auto; - justify-content: space-between; - position: relative; - z-index: 1; - background-color: @toolbar-background; - border-left: @toolbar-border-thickness solid @toolbar-border-color; -} - -.panel { - position: relative; - display: flex; - width: @toolbar-open-size; - background-color: @toolbar-background; - border-left: @toolbar-border-thickness solid @toolbar-border-color; - overflow: auto; - transition: @transition-slow; - pointer-events: auto; - - .root:not(.isOpen) & { - transform: translateX(@toolbar-open-size * 0.3); - opacity: 0; - pointer-events: none; - } -} - -.preference { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; -} diff --git a/src/Playroom/Toolbar/Toolbar.tsx b/src/Playroom/Toolbar/Toolbar.tsx index c79a8eef..df317cca 100644 --- a/src/Playroom/Toolbar/Toolbar.tsx +++ b/src/Playroom/Toolbar/Toolbar.tsx @@ -1,22 +1,20 @@ -import React, { useContext, ReactChild, useState, useCallback } from 'react'; +import React, { useContext, useState, useCallback } from 'react'; import { useTimeoutFn } from 'react-use'; import classnames from 'classnames'; import { PlayroomProps } from '../Playroom'; -import { StoreContext, EditorPosition } from '../../StoreContext/StoreContext'; +import { StoreContext } from '../../StoreContext/StoreContext'; import FramesPanel from '../FramesPanel/FramesPanel'; import PreviewPanel from '../PreviewPanel/PreviewPanel'; import Snippets from '../Snippets/Snippets'; import ToolbarItem from '../ToolbarItem/ToolbarItem'; import AddIcon from '../icons/AddIcon'; import FramesIcon from '../icons/FramesIcon'; -import EditorUndockedIcon from '../icons/EditorUndockedIcon'; -import EditorBottomIcon from '../icons/EditorBottomIcon'; -import EditorRightIcon from '../icons/EditorRightIcon'; import ShareIcon from '../icons/ShareIcon'; import PlayIcon from '../icons/PlayIcon'; -// @ts-ignore -import styles from './Toolbar.less'; +import * as styles from './Toolbar.css'; +import SettingsPanel from '../SettingsPanel/SettingsPanel'; +import SettingsIcon from '../icons/SettingsIcon'; interface Props { themes: PlayroomProps['themes']; @@ -24,31 +22,13 @@ interface Props { snippets: PlayroomProps['snippets']; } -interface Icon { - component: ReactChild; - title: string; -} -const positionIcon: Record = { - undocked: { - component: , - title: 'Undock into separate window ', - }, - right: { - component: , - title: 'Dock to right', - }, - bottom: { - component: , - title: 'Dock to bottom', - }, -}; +export const toolbarItemCount = 5; export default ({ themes: allThemes, widths: allWidths, snippets }: Props) => { const [ { visibleThemes = [], visibleWidths = [], - editorPosition, activeToolbarPanel, validCursorPosition, code, @@ -74,7 +54,7 @@ export default ({ themes: allThemes, widths: allWidths, snippets }: Props) => { const isSnippetsOpen = activeToolbarPanel === 'snippets'; const isFramesOpen = activeToolbarPanel === 'frames'; - const isPositionOpen = activeToolbarPanel === 'positions'; + const isSettingsOpen = activeToolbarPanel === 'settings'; const isPreviewOpen = activeToolbarPanel === 'preview'; const hasSnippets = snippets && snippets.length > 0; @@ -85,7 +65,7 @@ export default ({ themes: allThemes, widths: allWidths, snippets }: Props) => { return (
{isOpen && ( @@ -96,11 +76,7 @@ export default ({ themes: allThemes, widths: allWidths, snippets }: Props) => { )}
-
+
{hasSnippets && ( { dispatch({ type: 'toggleToolbar', - payload: { panel: 'positions' }, + payload: { panel: 'settings' }, }) } > - {positionIcon[editorPosition].component} +
- -
dispatch({ type: 'closeToolbar' })} - > - {Object.keys(positionIcon) - .filter((pos) => pos !== editorPosition) - .map((pos) => { - const position = pos as EditorPosition; - return position === 'undocked' ? null : ( - - ); - })} -
@@ -248,6 +193,13 @@ export default ({ themes: allThemes, widths: allWidths, snippets }: Props) => { >
+ +
diff --git a/src/Playroom/ToolbarItem/ToolbarItem.css.ts b/src/Playroom/ToolbarItem/ToolbarItem.css.ts new file mode 100644 index 00000000..400028af --- /dev/null +++ b/src/Playroom/ToolbarItem/ToolbarItem.css.ts @@ -0,0 +1,145 @@ +import { sprinkles, vars, colorPaletteVars } from '../sprinkles.css'; +import { style, globalStyle } from '@vanilla-extract/css'; + +export const toolbarItemSize = 60; + +export const success = style({}); +export const disabled = style({}); +export const showIndicator = style({}); +export const button_isActive = style({}); +export const button = style([ + sprinkles({ + position: 'relative', + border: 0, + padding: 'none', + appearance: 'none', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }), + { + outline: 'none', + height: toolbarItemSize, + width: toolbarItemSize, + color: 'currentColor', + backgroundColor: colorPaletteVars.background.surface, + WebkitTapHighlightColor: 'transparent', + + // Background + '::before': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + backgroundColor: colorPaletteVars.background.selection, + opacity: 0, + transition: vars.transition.slow, + pointerEvents: 'none', + }, + + // Side strip + '::after': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + right: 0, + width: '5px', + backgroundColor: 'currentColor', + transition: vars.transition.slow, + }, + + selectors: { + [`&${success}`]: { + color: colorPaletteVars.foreground.positive, + }, + + [`&:not(${disabled})`]: { + cursor: 'pointer', + }, + + [`&${disabled}`]: { + color: colorPaletteVars.foreground.neutralSoft, + }, + + [[ + `&${showIndicator}`, + `&${button_isActive}:not(${success}):not(${disabled})`, + `html:not([data-playroom-dark]) &:hover:not(${success}):not(${disabled})`, + ].join(',')]: { + color: colorPaletteVars.foreground.accent, + }, + + [`&:not(${success}):not(:hover):focus::before`]: { + color: colorPaletteVars.foreground.neutral, + }, + [[ + `&:not(${success}):not(${disabled}):focus::before`, + `&:not(${success}):not(${disabled}):hover::before`, + ].join(',')]: { + opacity: 1, + }, + + [`&:not(${button_isActive})::after`]: { + transform: 'translateX(100%)', + opacity: 0, + }, + }, + }, +]); + +export const show = style({}); +export const indicator = style([ + sprinkles({ + position: 'absolute', + borderRadius: 'full', + pointerEvents: 'none', + transition: 'fast', + }), + { + top: '12px', + right: '12px', + height: '10px', + width: '10px', + backgroundColor: colorPaletteVars.background.accent, + border: `2px solid ${colorPaletteVars.background.surface}`, + selectors: { + [`&:not(${show})`]: { + transform: 'scale(0)', + opacity: 0, + }, + }, + }, +]); + +export const successIndicator = style([ + sprinkles({ + position: 'absolute', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + borderRadius: 'full', + pointerEvents: 'none', + transition: 'fast', + }), + { + top: '12px', + right: '12px', + height: '14px', + width: '14px', + backgroundColor: colorPaletteVars.foreground.positive, + border: `2px solid ${colorPaletteVars.background.surface}`, + selectors: { + [`&:not(${show})`]: { + transform: 'translate3d(-15px, 9px, 0) scale(0)', + opacity: 0, + }, + }, + }, +]); + +globalStyle(`${successIndicator} svg`, { + color: colorPaletteVars.foreground.neutralInverted, +}); diff --git a/src/Playroom/ToolbarItem/ToolbarItem.less b/src/Playroom/ToolbarItem/ToolbarItem.less deleted file mode 100644 index 5476a5bd..00000000 --- a/src/Playroom/ToolbarItem/ToolbarItem.less +++ /dev/null @@ -1,120 +0,0 @@ -@import (reference) '../variables.less'; - -.button { - position: relative; - height: @toolbar-closed-size; - width: @toolbar-closed-size; - border: 0; - padding: 0; - background-color: @toolbar-background; - -webkit-tap-highlight-color: transparent; - appearance: none; - outline: none; - display: flex; - align-items: center; - justify-content: center; - color: currentColor; - height: @toolbar-item-size; - width: @toolbar-item-size; - - &.success { - color: @positive; - } - - &:not(.disabled) { - cursor: pointer; - } - - &.disabled { - color: @gray-3; - } - - &.showIndicator, - &.button_isActive:not(.success):not(.disabled), - &:hover:not(.success):not(.disabled) { - color: @toolbar-highlight; - } - - // Background - &:before { - content: ''; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - background-color: currentColor; - opacity: 0; - transition: @transition-slow; - pointer-events: none; - - :not(.success):not(:hover):focus& { - color: @toolbar-foregound; - } - - :not(.success):not(.disabled):not(.button_isActive):focus&, - :not(.success):not(.disabled):hover& { - opacity: 0.1; - } - } - - // Side strip - &:after { - content: ''; - position: absolute; - top: 0; - bottom: 0; - right: 0; - width: 5px; - background-color: currentColor; - transition: @transition-slow; - - :not(.button_isActive)& { - transform: translateX(100%); - opacity: 0; - } - } -} - -.indicator { - position: absolute; - top: 12px; - right: 12px; - height: 10px; - width: 10px; - border-radius: 100%; - background-color: @toolbar-highlight; - border: 2px solid @toolbar-background; - pointer-events: none; - transition: @transition-fast; - - &:not(.show) { - transform: scale(0); - opacity: 0; - } -} - -.successIndicator { - position: absolute; - top: 12px; - right: 12px; - height: 14px; - width: 14px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 100%; - background-color: @positive; - border: 2px solid @toolbar-background; - pointer-events: none; - transition: @transition-fast; - - svg { - color: @white; - } - - &:not(.show) { - transform: translate3d(-15px, 9px, 0) scale(0); - opacity: 0; - } -} diff --git a/src/Playroom/ToolbarItem/ToolbarItem.tsx b/src/Playroom/ToolbarItem/ToolbarItem.tsx index 90e85ddc..7a433190 100644 --- a/src/Playroom/ToolbarItem/ToolbarItem.tsx +++ b/src/Playroom/ToolbarItem/ToolbarItem.tsx @@ -2,8 +2,7 @@ import React, { ReactChild } from 'react'; import classnames from 'classnames'; import TickIcon from '../icons/TickIcon'; -// @ts-ignore -import styles from './ToolbarItem.less'; +import * as styles from './ToolbarItem.css'; interface Props { children: ReactChild; @@ -34,24 +33,25 @@ export default ({ [styles.disabled]: disabled, [styles.success]: success, })} + disabled={disabled} title={title} onClick={(event) => { event.stopPropagation(); onClick(); }} > - {children} -
{children} + -
-
+
); diff --git a/src/Playroom/ToolbarPanel/ToolbarPanel.css.ts b/src/Playroom/ToolbarPanel/ToolbarPanel.css.ts new file mode 100644 index 00000000..739d6a62 --- /dev/null +++ b/src/Playroom/ToolbarPanel/ToolbarPanel.css.ts @@ -0,0 +1,5 @@ +import { sprinkles } from '../sprinkles.css'; + +export const root = sprinkles({ + padding: 'xxlarge', +}); diff --git a/src/Playroom/ToolbarPanel/ToolbarPanel.less b/src/Playroom/ToolbarPanel/ToolbarPanel.less deleted file mode 100644 index 2a123c75..00000000 --- a/src/Playroom/ToolbarPanel/ToolbarPanel.less +++ /dev/null @@ -1,5 +0,0 @@ -@import (reference) '../variables.less'; - -.root { - padding: (@grid * 6); -} diff --git a/src/Playroom/ToolbarPanel/ToolbarPanel.tsx b/src/Playroom/ToolbarPanel/ToolbarPanel.tsx index 65ebca79..d7232210 100644 --- a/src/Playroom/ToolbarPanel/ToolbarPanel.tsx +++ b/src/Playroom/ToolbarPanel/ToolbarPanel.tsx @@ -1,8 +1,6 @@ import React, { ElementType, ReactNode } from 'react'; -import classnames from 'classnames'; -// @ts-ignore -import styles from './ToolbarPanel.less'; +import * as styles from './ToolbarPanel.css'; interface Props { children: ReactNode; @@ -18,7 +16,7 @@ export const ToolbarPanel = ({ React.createElement( component, { - className: classnames(styles.root), + className: styles.root, 'data-testid': dataTestId, }, children diff --git a/src/Playroom/icons/ChevronIcon.css.ts b/src/Playroom/icons/ChevronIcon.css.ts new file mode 100644 index 00000000..81205f85 --- /dev/null +++ b/src/Playroom/icons/ChevronIcon.css.ts @@ -0,0 +1,19 @@ +import { style } from '@vanilla-extract/css'; +import { vars } from '../sprinkles.css'; + +export const root = style({ + transition: vars.transition.medium, + transformOrigin: '50% 50%', +}); + +export const left = style({ + transform: 'rotate(90deg)', +}); + +export const up = style({ + transform: 'rotate(180deg)', +}); + +export const right = style({ + transform: 'rotate(270deg)', +}); diff --git a/src/Playroom/icons/ChevronIcon.less b/src/Playroom/icons/ChevronIcon.less deleted file mode 100644 index d22e4ea8..00000000 --- a/src/Playroom/icons/ChevronIcon.less +++ /dev/null @@ -1,15 +0,0 @@ -@import (reference) '../variables.less'; - -.root { - transition: @transition-medium; - transform-origin: 50% 50%; -} -.left { - transform: rotate(90deg); -} -.up { - transform: rotate(180deg); -} -.right { - transform: rotate(270deg); -} diff --git a/src/Playroom/icons/ChevronIcon.tsx b/src/Playroom/icons/ChevronIcon.tsx index cf6848d8..836132b4 100644 --- a/src/Playroom/icons/ChevronIcon.tsx +++ b/src/Playroom/icons/ChevronIcon.tsx @@ -1,8 +1,7 @@ import React, { SVGProps } from 'react'; import classnames from 'classnames'; -// @ts-ignore -import styles from './ChevronIcon.less'; +import * as styles from './ChevronIcon.css'; interface ChevronSvgProps extends SVGProps { direction?: 'down' | 'up' | 'left' | 'right'; diff --git a/src/Playroom/icons/ColorModeDarkIcon.tsx b/src/Playroom/icons/ColorModeDarkIcon.tsx new file mode 100644 index 00000000..3ea5eaf5 --- /dev/null +++ b/src/Playroom/icons/ColorModeDarkIcon.tsx @@ -0,0 +1,14 @@ +import React from 'react'; + +export default () => ( + + + +); diff --git a/src/Playroom/icons/ColorModeLightIcon.tsx b/src/Playroom/icons/ColorModeLightIcon.tsx new file mode 100644 index 00000000..0fdbd7dc --- /dev/null +++ b/src/Playroom/icons/ColorModeLightIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +export default () => ( + + + + + + + + + + + +); diff --git a/src/Playroom/icons/ColorModeSystemIcon.tsx b/src/Playroom/icons/ColorModeSystemIcon.tsx new file mode 100644 index 00000000..9932834b --- /dev/null +++ b/src/Playroom/icons/ColorModeSystemIcon.tsx @@ -0,0 +1,14 @@ +import React from 'react'; + +export default () => ( + + + +); diff --git a/src/Playroom/icons/SettingsIcon.tsx b/src/Playroom/icons/SettingsIcon.tsx new file mode 100644 index 00000000..4dbd123e --- /dev/null +++ b/src/Playroom/icons/SettingsIcon.tsx @@ -0,0 +1,16 @@ +import React from 'react'; + +export default () => ( + + + + +); diff --git a/src/Playroom/palettes.ts b/src/Playroom/palettes.ts new file mode 100644 index 00000000..3fa4fdfd --- /dev/null +++ b/src/Playroom/palettes.ts @@ -0,0 +1,162 @@ +import { transparentize, mix, darken } from 'polished'; + +const originalPalette = { + blue0: '#e5f3ff', + blue1: '#0088ff', + blue2: '#005ad2', + blue3: '#00439c', + blue4: '#040080', + green1: '#c5f5e9', + green2: '#1da584', + red1: '#fee1e9', + red2: '#e52b50', + red3: '#cd193d', + purple: '#75438a', + white: '#fff', + gray1: '#f4f4f4', + gray2: '#e8e8e8', + gray3: '#a7a7a7', + gray4: '#767676', + gray5: '#515151', + gray6: '#1e1e1e', + black: '#000', +}; + +export const light = { + code: { + text: originalPalette.black, + tag: originalPalette.blue4, + attribute: originalPalette.blue2, + string: originalPalette.blue3, + atom: originalPalette.blue3, + variable: originalPalette.blue1, + number: originalPalette.purple, + }, + foreground: { + neutralSoft: originalPalette.gray3, + neutral: originalPalette.gray5, + neutralInverted: originalPalette.white, + secondary: originalPalette.gray3, + critical: originalPalette.red3, + accent: originalPalette.blue2, + positive: originalPalette.green2, + }, + background: { + transparent: 'rgba(0, 0, 0, .05)', + accent: originalPalette.blue2, + positive: originalPalette.green1, + critical: originalPalette.red1, + neutral: originalPalette.gray6, + surface: originalPalette.white, + body: originalPalette.gray1, + selection: originalPalette.blue0, + }, + border: { + standard: originalPalette.gray2, + }, + shadows: { + small: '0 2px 8px rgba(18, 21, 26, 0.3)', + focus: `0 0 0 5px ${originalPalette.blue0}`, + }, +}; + +const seekPalette = { + grey: { + 900: '#0f131b', + 800: '#1c2230', + 700: '#2d3648', + 600: '#3d4b63', + 500: '#5b6881', + 400: '#828ea4', + 300: '#abb3c1', + 200: '#d2d7de', + 100: '#e8ecf0', + 50: '#f6f8fa', + }, + mint: { + 900: '#033720', + 800: '#0a5334', + 700: '#13774f', + 600: '#18986a', + 500: '#28b888', + 400: '#57cea9', + 300: '#88dec5', + 200: '#beeddf', + 100: '#e1f7f1', + 50: '#f3fdfa', + }, + red: { + 900: '#730706', + 800: '#941110', + 700: '#b71f1f', + 600: '#db2d2d', + 500: '#f94344', + 400: '#fa6b6c', + 300: '#fb999a', + 200: '#fdc8c8', + 100: '#ffe3e2', + 50: '#fef2f2', + }, + purple: { + 900: '#1d0a63', + 800: '#341b85', + 700: '#502eaa', + 600: '#6a40cc', + 500: '#8b5ceb', + 400: '#aa83f2', + 300: '#c6aaf5', + 200: '#e1d1f9', + 100: '#f1e7fc', + 50: '#f9f5fe', + }, + blue: { + 900: '#052253', + 800: '#103975', + 700: '#1e549b', + 600: '#296fc0', + 500: '#3e8fe0', + 400: '#68aeea', + 300: '#97c8f1', + 200: '#c8e1f7', + 100: '#e2f1fb', + 50: '#f3faff', + }, +}; + +export const dark = { + code: { + text: seekPalette.grey[50], + tag: seekPalette.blue[200], + attribute: seekPalette.blue[400], + string: seekPalette.blue[300], + atom: seekPalette.blue[300], + variable: seekPalette.blue[500], + number: seekPalette.purple[400], + }, + foreground: { + neutralSoft: seekPalette.grey[600], + neutral: seekPalette.grey[50], + neutralInverted: originalPalette.black, + secondary: seekPalette.grey[400], + critical: seekPalette.red[400], + accent: seekPalette.blue[500], + positive: seekPalette.mint[500], + }, + background: { + transparent: 'rgba(0, 0, 0, .15)', + accent: seekPalette.blue[500], + positive: mix(0.6, seekPalette.grey[900], seekPalette.mint[500]), + critical: mix(0.7, seekPalette.grey[900], seekPalette.red[600]), + neutral: seekPalette.grey[800], + surface: seekPalette.grey[900], + body: darken(0.03, seekPalette.grey[900]), + selection: transparentize(0.85, seekPalette.blue[600]), + }, + border: { + standard: seekPalette.grey[800], + }, + shadows: { + small: `0 0 10px -2px ${seekPalette.grey[700]}`, + focus: `0 0 0 5px ${transparentize(0.6, seekPalette.blue[400])}`, + }, +}; diff --git a/src/Playroom/sprinkles.css.ts b/src/Playroom/sprinkles.css.ts new file mode 100644 index 00000000..7ec5b6bc --- /dev/null +++ b/src/Playroom/sprinkles.css.ts @@ -0,0 +1,148 @@ +import { createGlobalTheme, createThemeContract } from '@vanilla-extract/css'; +import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; +import { dark, light } from './palettes'; + +const fontFamily = 'Helvetica, arial, sans-serif'; +export const vars = createGlobalTheme(':root', { + font: { + family: { + standard: fontFamily, + code: 'Source Code Pro, Firacode, Hasklig, Menlo, monospace', + }, + scale: { + xsmall: `normal 10px ${fontFamily}`, + small: `normal 12px ${fontFamily}`, + standard: `normal 14px ${fontFamily}`, + large: `normal 16px/1.3em ${fontFamily}`, + }, + weight: { + weak: '100', + strong: '700', + }, + }, + grid: '4px', + radii: { + small: '2px', + medium: '4px', + large: '6px', + full: '100%', + }, + codeGutterSize: '70px', + touchableSize: '44px', + transition: { + slow: 'opacity 300ms ease, transform 300ms ease', + medium: 'opacity 200ms ease, transform 200ms ease', + fast: 'opacity 100ms ease, transform 100ms ease', + }, + space: { + none: '0', + xxsmall: '2px', + xsmall: '4px', + medium: '6px', + large: '12px', + xlarge: '16px', + xxlarge: '20px', + gutter: '40px', + }, +}); + +export const colorPaletteVars = createThemeContract({ + code: { + text: null, + tag: null, + attribute: null, + string: null, + atom: null, + variable: null, + number: null, + }, + foreground: { + neutralSoft: null, + neutral: null, + neutralInverted: null, + secondary: null, + critical: null, + accent: null, + positive: null, + }, + background: { + transparent: null, + accent: null, + positive: null, + critical: null, + neutral: null, + surface: null, + body: null, + selection: null, + }, + border: { + standard: null, + }, + shadows: { + small: null, + focus: null, + }, +}); + +createGlobalTheme(':root', colorPaletteVars, light); +createGlobalTheme(':root[data-playroom-dark]', colorPaletteVars, dark); + +const responsiveProperties = defineProperties({ + properties: { + position: ['absolute', 'relative', 'fixed'], + top: [0], + bottom: [0], + left: [0], + right: [0], + display: ['none', 'flex', 'block', 'inline'], + flexDirection: ['row', 'column', 'row-reverse'], + flexWrap: ['wrap'], + justifyContent: [ + 'stretch', + 'flex-start', + 'center', + 'flex-end', + 'space-around', + 'space-between', + ], + alignItems: ['stretch', 'flex-start', 'center', 'flex-end'], + paddingTop: vars.space, + paddingBottom: vars.space, + paddingLeft: vars.space, + paddingRight: vars.space, + marginTop: vars.space, + marginBottom: vars.space, + marginLeft: vars.space, + marginRight: vars.space, + overflow: ['hidden', 'auto'], + boxShadow: colorPaletteVars.shadows, + borderRadius: vars.radii, + transition: vars.transition, + cursor: ['pointer'], + pointerEvents: ['none', 'auto'], + userSelect: ['none'], + appearance: ['none'], + opacity: [0], + zIndex: [0, 1], + font: vars.font.scale, + fontWeight: vars.font.weight, + width: { full: '100%', viewport: '100vw' }, + height: { full: '100%', viewport: '100vh' }, + whiteSpace: ['nowrap'], + boxSizing: ['border-box'], + textAlign: ['center', 'left', 'right'], + border: [0], + }, + shorthands: { + inset: ['top', 'bottom', 'left', 'right'], + padding: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'], + paddingX: ['paddingLeft', 'paddingRight'], + paddingY: ['paddingTop', 'paddingBottom'], + margin: ['marginTop', 'marginBottom', 'marginLeft', 'marginRight'], + marginX: ['marginLeft', 'marginRight'], + marginY: ['marginTop', 'marginBottom'], + placeItems: ['justifyContent', 'alignItems'], + }, +}); + +export const sprinkles = createSprinkles(responsiveProperties); diff --git a/src/Playroom/variables.less b/src/Playroom/variables.less deleted file mode 100644 index 113f2678..00000000 --- a/src/Playroom/variables.less +++ /dev/null @@ -1,108 +0,0 @@ -// Grid -@grid: 4px; -@gutter-width: @grid * 10; -@interaction-height: @grid * 11; - -// Field -@field-gutter: @grid * 4; - -// Typography -@typography-family: Helvetica, arial, sans-serif; -@text-large: normal 16px/1.3em @typography-family; -@text-standard: normal 14px @typography-family; -@text-small: normal 12px @typography-family; -@text-xsmall: normal 10px @typography-family; -@text-neutral: @gray-5; - -// Weight -@bold: 700; -@weak: 100; - -// Palette -@blue-1: #0088ff; -@blue-2: #005ad2; -@blue-3: #00439c; -@blue-4: #040080; -@green-1: #c5f5e9; -@green-2: #1da584; -@red-1: #fed6e1; -@red-2: #e52b50; -@red-3: #c3183a; -@white: #fff; -@gray-1: #f4f4f4; -@gray-2: #e8e8e8; -@gray-3: #a7a7a7; -@gray-4: #767676; -@gray-5: #515151; -@gray-6: #1e1e1e; -@black: #000; - -// Tones -@positive-light: @green-1; -@positive: @green-2; -@critical-light: @red-1; -@critical: @red-2; -@critical-dark: @red-3; -@neutral: @gray-2; - -// Highlights -@highlight: @blue-2; -@selection: fade(@blue-2, 10%); - -// Box Shadow: -@shadow-small: 0 2px 8px rgba(18, 21, 26, 0.3); -@focus-outline: 0 0 0 5px rgba(@highlight, 0.15); - -// Border radii -@radius-small: 2px; -@radius-medium: 4px; -@radius-large: 6px; - -// Transitions -@transition-speed-fast: 100ms; -@transition-speed-medium: 200ms; -@transition-speed-slow: 300ms; -@transition-fast: opacity @transition-speed-fast ease, - transform @transition-speed-fast ease; -@transition-medium: opacity @transition-speed-medium ease, - transform @transition-speed-medium ease; -@transition-slow: opacity @transition-speed-slow ease, - transform @transition-speed-slow ease; - -// Playroom -@body: @gray-1; - -// Preview -@preview-padding: @gutter-width; -@preview-inactive-label-opacity: 0.3; - -// Code Editor -@code-background: @white; -@code-font-family: Source Code Pro, Firacode, Hasklig, Menlo, monospace; -@code-gutter-size: @gutter-width * 1.75; -@code-format-tag: @blue-4; -@code-format-attribute: @blue-2; -@code-format-string: @blue-3; -@code-format-atom: @blue-3; -@code-format-variable: @blue-1; -@code-hint-bg: @blue-1; -@code-hint-fg: @white; -@code-selection: @selection; - -// Toolbar -@toolbar-closed-size: 60px; -@toolbar-open-size: 300px; -@toolbar-item-size: 60px; -@toolbar-max-item-count: 5; -@toolbar-foregound: @text-neutral; -@toolbar-background: @white; -@toolbar-highlight: @highlight; -@toolbar-border-color: @gray-2; -@toolbar-border-thickness: 1px; - -// Snippets -@snippet-background: @toolbar-background; -@snippet-foreground: @toolbar-foregound; -@snippet-highlight: @toolbar-highlight; -@snippet-selection: @selection; -@snippet-gutter: @grid * 2; diff --git a/src/StoreContext/StoreContext.tsx b/src/StoreContext/StoreContext.tsx index 3472e6ff..52ac7de0 100644 --- a/src/StoreContext/StoreContext.tsx +++ b/src/StoreContext/StoreContext.tsx @@ -28,6 +28,13 @@ const store = localforage.createInstance({ const defaultPosition = 'bottom'; export type EditorPosition = 'bottom' | 'right' | 'undocked'; +export type ColorScheme = 'light' | 'dark' | 'system'; + +const applyColorScheme = (colorScheme: Exclude) => { + document.documentElement[ + colorScheme === 'dark' ? 'setAttribute' : 'removeAttribute' + ]('data-playroom-dark', ''); +}; interface DebounceUpdateUrl { code?: string; @@ -45,7 +52,7 @@ interface StatusMessage { tone: 'positive' | 'critical'; } -type ToolbarPanel = 'snippets' | 'frames' | 'positions' | 'preview'; +type ToolbarPanel = 'snippets' | 'frames' | 'preview' | 'settings'; interface State { code: string; previewRenderCode?: string; @@ -62,6 +69,7 @@ interface State { visibleThemes?: string[]; visibleWidths?: number[]; ready: boolean; + colorScheme: ColorScheme; } type Action = @@ -82,6 +90,10 @@ type Action = payload: { url: string; trigger: 'toolbarItem' | 'previewPanel' }; } | { type: 'dismissMessage' } + | { + type: 'updateColorScheme'; + payload: { colorScheme: ColorScheme }; + } | { type: 'updateEditorPosition'; payload: { position: EditorPosition }; @@ -280,13 +292,22 @@ const createReducer = ({ }; } + case 'updateColorScheme': { + const { colorScheme } = action.payload; + store.setItem('colorScheme', colorScheme); + + return { + ...state, + colorScheme, + }; + } + case 'updateEditorPosition': { const { position } = action.payload; - const { activeToolbarPanel, ...currentState } = state; store.setItem('editorPosition', position); return { - ...currentState, + ...state, editorPosition: position, }; } @@ -372,6 +393,7 @@ const initialState: State = { editorHeight: 300, editorWidth: 360, ready: false, + colorScheme: 'light', }; export const StoreContext = createContext([ @@ -432,7 +454,8 @@ export const StoreProvider = ({ number | null, number | null, number[] | null, - string[] | null + string[] | null, + ColorScheme | null >([ store.getItem('code'), store.getItem('editorPosition'), @@ -440,6 +463,7 @@ export const StoreProvider = ({ store.getItem('editorWidth'), store.getItem('visibleWidths'), store.getItem('visibleThemes'), + store.getItem('colorScheme'), ]).then( ([ storedCode, @@ -448,6 +472,7 @@ export const StoreProvider = ({ storedWidth, storedVisibleWidths, storedVisibleThemes, + storedColorScheme, ]) => { const code = codeFromQuery || storedCode || exampleCode; const editorPosition = storedPosition; @@ -456,6 +481,7 @@ export const StoreProvider = ({ const visibleWidths = widthsFromQuery || storedVisibleWidths; const visibleThemes = hasThemesConfigured && (themesFromQuery || storedVisibleThemes); + const colorScheme = storedColorScheme; dispatch({ type: 'initialLoad', @@ -466,6 +492,7 @@ export const StoreProvider = ({ ...(editorWidth ? { editorWidth } : {}), ...(visibleThemes ? { visibleThemes } : {}), ...(visibleWidths ? { visibleWidths } : {}), + ...(colorScheme ? { colorScheme } : {}), ready: true, }, }); @@ -473,6 +500,24 @@ export const StoreProvider = ({ ); }, [hasThemesConfigured]); + useEffect(() => { + const mq = window.matchMedia('(prefers-color-scheme: dark)'); + + if (state.colorScheme === 'system') { + const handler = (e: MediaQueryListEvent) => { + applyColorScheme(e.matches ? 'dark' : 'light'); + }; + mq.addEventListener('change', handler); + applyColorScheme(mq.matches ? 'dark' : 'light'); + + return () => { + mq.removeEventListener('change', handler); + }; + } + + applyColorScheme(state.colorScheme); + }, [state.colorScheme]); + useEffect(() => { debouncedCodeUpdate({ code: state.code, diff --git a/src/utils/cursor.ts b/src/utils/cursor.ts index 89b50206..e211e239 100644 --- a/src/utils/cursor.ts +++ b/src/utils/cursor.ts @@ -1,4 +1,4 @@ -import { CursorPosition } from './../StoreContext/StoreContext'; +import { CursorPosition } from '../StoreContext/StoreContext'; import { validateCode } from './compileJsx'; const breakoutString = '"b"'; diff --git a/src/utils/formatting.ts b/src/utils/formatting.ts index 68d6a501..a1819bf0 100644 --- a/src/utils/formatting.ts +++ b/src/utils/formatting.ts @@ -1,6 +1,6 @@ import prettier from 'prettier/standalone'; import babel from 'prettier/parser-babel'; -import { CursorPosition } from './../StoreContext/StoreContext'; +import { CursorPosition } from '../StoreContext/StoreContext'; import { insertAtCursor } from './cursor'; export interface CodeWithCursor { diff --git a/src/utils/usePreviewUrl.ts b/src/utils/usePreviewUrl.ts index 44499bfd..ec225ddf 100644 --- a/src/utils/usePreviewUrl.ts +++ b/src/utils/usePreviewUrl.ts @@ -1,6 +1,6 @@ import { useContext } from 'react'; -import { StoreContext } from './../StoreContext/StoreContext'; +import { StoreContext } from '../StoreContext/StoreContext'; import { createPreviewUrl } from '../../utils'; import playroomConfig from '../config'; diff --git a/yarn.lock b/yarn.lock index 38e26b7b..997644cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -905,6 +905,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.16.7": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/standalone@^7.13.11": version "7.13.11" resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.13.11.tgz#d732c9f2780480d54ebb4d1e49c76b2466d40270" @@ -1136,6 +1143,11 @@ debug "^3.1.0" lodash.once "^4.1.1" +"@emotion/hash@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== + "@eslint/eslintrc@^0.4.0": version "0.4.0" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.0.tgz#99cc0a0584d72f1df38b900fb062ba995f395547" @@ -1765,6 +1777,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== +"@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -1945,6 +1962,86 @@ "@typescript-eslint/types" "4.18.0" eslint-visitor-keys "^2.0.0" +"@vanilla-extract/babel-plugin@^1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@vanilla-extract/babel-plugin/-/babel-plugin-1.1.5.tgz#dcd1cd33979a7162135d3fc94a977b533764cf1d" + integrity sha512-wt2Sxgt2ZzslwwTDaZFGdrf0yUsoadOwAM73R6Gzv/1UJSzIdThVss/5JSwVO4RKvnus+0I1Iiq8pWqSJsRbCQ== + dependencies: + "@babel/core" "^7.13.10" + "@babel/template" "^7.12.13" + "@vanilla-extract/integration" "^3.0.0" + +"@vanilla-extract/css-utils@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@vanilla-extract/css-utils/-/css-utils-0.1.2.tgz#6bcd3e45f187d56c319ce9bc36ae1814b373c581" + integrity sha512-qoxIu5E/UhJtoKsPL1JaU9nhTN0Xl5zYV0pScOgsvc3JN46TvTTt0L3GV8x3PQpZP7x3elw8BsC9czYbhJy9Gg== + +"@vanilla-extract/css@^1.6.8": + version "1.6.8" + resolved "https://registry.yarnpkg.com/@vanilla-extract/css/-/css-1.6.8.tgz#21796c6e11d010a22422185bacf5b65cbd294da8" + integrity sha512-wkZay2jWe9a3Dt30j+WTJicK4+YV7i65lr+QnpkigVY9uU2KPzaiASEyUV8AouT2cZm7AOhteBBVKI8cYeWnVQ== + dependencies: + "@emotion/hash" "^0.8.0" + "@vanilla-extract/private" "^1.0.3" + chalk "^4.1.1" + css-what "^5.0.1" + cssesc "^3.0.0" + csstype "^3.0.7" + deep-object-diff "^1.1.0" + deepmerge "^4.2.2" + escape-string-regexp "^4.0.0" + outdent "^0.8.0" + +"@vanilla-extract/css@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@vanilla-extract/css/-/css-1.7.0.tgz#7276830c7741b17b7a70720be88c9083682f5206" + integrity sha512-2Abpr5aJskwKS+waMWxWnTBqq/rj4J93KtGteW0VSORMUsijrupwjOXECd7Llh+nSFfx/Y6usuexF5/ffyDF8A== + dependencies: + "@emotion/hash" "^0.8.0" + "@vanilla-extract/private" "^1.0.3" + chalk "^4.1.1" + css-mediaquery "^0.1.2" + css-what "^5.0.1" + cssesc "^3.0.0" + csstype "^3.0.7" + deep-object-diff "^1.1.0" + deepmerge "^4.2.2" + escape-string-regexp "^4.0.0" + outdent "^0.8.0" + +"@vanilla-extract/integration@^3.0.0", "@vanilla-extract/integration@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@vanilla-extract/integration/-/integration-3.0.1.tgz#7f4bb01667f65f745fae3d9e39be699b115839d5" + integrity sha512-4G4WgkalVRIsJyDb/X08S0xcG2eDm1RJvqIgji0D7HvOSeyD+nvPEhbq8FAxs7MeVyyPDoCWsCKQvS3f9jz9UA== + dependencies: + "@vanilla-extract/css" "^1.6.8" + esbuild "^0.11.16" + eval "0.1.6" + find-up "^5.0.0" + javascript-stringify "^2.0.1" + lodash "^4.17.21" + outdent "^0.8.0" + +"@vanilla-extract/private@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@vanilla-extract/private/-/private-1.0.3.tgz#7ec72bc2ff6fe51f9d650f962e8d1989b073690f" + integrity sha512-17kVyLq3ePTKOkveHxXuIJZtGYs+cSoev7BlP+Lf4916qfDhk/HBjvlYDe8egrea7LNPHKwSZJK/bzZC+Q6AwQ== + +"@vanilla-extract/sprinkles@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@vanilla-extract/sprinkles/-/sprinkles-1.4.0.tgz#acad9c9470a41b8350ae97efc02bb33e52553bcf" + integrity sha512-q9Tu5bHkN/fT0IFkBDEsNeTKN/8CFYkgGVDw0iZ+wM/n9IKhWrKLnOjDk1v9NpCXD3rUQqDipl0pdGCEcBe4RQ== + +"@vanilla-extract/webpack-plugin@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@vanilla-extract/webpack-plugin/-/webpack-plugin-2.1.8.tgz#52fac541bb9ff69c6a8d2577d634da815555793c" + integrity sha512-iz4UkLlco+QpguV76VIT9PiwEUTTpFrxwffik41dY8tWrBZgg8riCi/GnkJgjpv04sLrWFmeuTEeJ7npAW0ELw== + dependencies: + "@vanilla-extract/integration" "^3.0.1" + chalk "^4.1.1" + debug "^4.3.1" + loader-utils "^2.0.0" + "@webassemblyjs/ast@1.11.0": version "1.11.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.0.tgz#a5aa679efdc9e51707a4207139da57920555961f" @@ -2176,11 +2273,25 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + ajv@6.5.3: version "6.5.3" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9" @@ -2211,6 +2322,16 @@ ajv@^7.0.2: require-from-string "^2.0.2" uri-js "^4.2.2" +ajv@^8.0.0, ajv@^8.8.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ansi-align@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" @@ -2522,18 +2643,6 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@^10.2.5: - version "10.2.5" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.5.tgz#096a0337dbc96c0873526d7fef5de4428d05382d" - integrity sha512-7H4AJZXvSsn62SqZyJCP+1AWwOuoYpUfK6ot9vm0e87XD6mT8lDywc9D9OTJPMULyGcvmIxzTAMeG2Cc+YX+fA== - dependencies: - browserslist "^4.16.3" - caniuse-lite "^1.0.30001196" - colorette "^1.2.2" - fraction.js "^4.0.13" - normalize-range "^0.1.2" - postcss-value-parser "^4.1.0" - available-typed-arrays@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" @@ -2712,11 +2821,6 @@ before-after-hook@^2.2.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.0.tgz#09c40d92e936c64777aa385c4e9b904f8147eaf0" integrity sha512-jH6rKQIfroBbhEXVmI7XmXe3ix5S/PgJqpzdDPnR8JGLHWNYLsYZ6tK5iWOF/Ra3oqEX0NobXGlzbiylIzVphQ== -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== - big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -2987,11 +3091,6 @@ camelcase-keys@^6.2.2: map-obj "^4.0.0" quick-lru "^4.0.1" -camelcase@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= - camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" @@ -3007,10 +3106,10 @@ camelcase@^6.0.0, camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== -caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001196: - version "1.0.30001202" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001202.tgz#4cb3bd5e8a808e8cd89e4e66c549989bc8137201" - integrity sha512-ZcijQNqrcF8JNLjzvEiXqX4JUYxoZa7Pvcsd9UD8Kz4TvhTonOSNRsK+qtvpVL4l6+T1Rh4LFtLfnNWg6BGWCQ== +caniuse-lite@^1.0.30001181: + version "1.0.30001322" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001322.tgz" + integrity sha512-neRmrmIrCGuMnxGSoh+x7zYtQFFgnSY2jaomjU56sCkTA6JINqQrxutF459JpWcWRajvoyn95sOXq4Pqrnyjew== capture-exit@^2.0.0: version "2.0.0" @@ -3074,6 +3173,14 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -3692,13 +3799,6 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== -copy-anything@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.3.tgz#842407ba02466b0df844819bbe3baebbe5d45d87" - integrity sha512-GK6QUtisv4fNS+XcI7shX0Gx9ORg7QqIznyfho79JTnX1XhLiyZHfftvGiziqzRiEi/Bjhgpi+D2o7HxJFPnDQ== - dependencies: - is-what "^3.12.0" - copy-concurrently@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" @@ -3819,6 +3919,11 @@ css-loader@^5.1.3: schema-utils "^3.0.0" semver "^7.3.4" +css-mediaquery@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0" + integrity sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA= + css-select@^2.0.2: version "2.1.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" @@ -3842,6 +3947,11 @@ css-what@^3.2.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== +css-what@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" + integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -3869,6 +3979,11 @@ csstype@^3.0.2, csstype@^3.0.6: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b" integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g== +csstype@^3.0.7: + version "3.0.11" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" + integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== + current-git-branch@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/current-git-branch/-/current-git-branch-1.1.0.tgz#3730e71ee024ed27dab16d740e5b1ea4774fa49f" @@ -4031,13 +4146,20 @@ debug@4.3.2: dependencies: ms "2.1.2" -debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: +debug@^3.1.0, debug@^3.1.1: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" +debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -4114,6 +4236,11 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deep-object-diff@^1.1.0: + version "1.1.7" + resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.7.tgz#348b3246f426427dd633eaa50e1ed1fc2eafc7e4" + integrity sha512-QkgBca0mL08P6HiOjoqvmm6xOAl2W6CT2+34Ljhg0OeFan8cwlcdq8jrLKsBBuUFAZLsN5b6y491KdKEoSo9lg== + deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" @@ -4442,11 +4569,6 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - emojis-list@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" @@ -4514,7 +4636,7 @@ err-code@^1.0.0: resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= -errno@^0.1.1, errno@~0.1.7: +errno@~0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== @@ -4597,6 +4719,11 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +esbuild@^0.11.16: + version "0.11.23" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.23.tgz#c42534f632e165120671d64db67883634333b4b8" + integrity sha512-iaiZZ9vUF5wJV8ob1tl+5aJTrwDczlvGP0JoMmnpC2B0ppiMCu8n8gmy5ZTGl5bcG081XBVn+U+jP+mPFm5T5Q== + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -4617,6 +4744,11 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + escodegen@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" @@ -4858,6 +4990,13 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +eval@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.6.tgz#9620d7d8c85515e97e6b47c5814f46ae381cb3cc" + integrity sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ== + dependencies: + require-like ">= 0.1.1" + event-stream@=3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" @@ -5429,11 +5568,6 @@ forwarded@~0.1.2: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= -fraction.js@^4.0.13: - version "4.0.13" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.0.13.tgz#3c1c315fa16b35c85fffa95725a36fa729c69dfe" - integrity sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA== - fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" @@ -6207,7 +6341,7 @@ i@0.3.x: resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0= -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -6253,11 +6387,6 @@ ignore@^5.1.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== -image-size@~0.5.0: - version "0.5.5" - resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" - integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= - immediate@~3.0.5: version "3.0.6" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" @@ -6853,11 +6982,6 @@ is-weakset@^2.0.1: resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83" integrity sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw== -is-what@^3.12.0: - version "3.14.1" - resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1" - integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA== - is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -6964,6 +7088,11 @@ java-properties@^1.0.0: resolved "https://registry.yarnpkg.com/java-properties/-/java-properties-1.0.2.tgz#ccd1fa73907438a5b5c38982269d0e771fe78211" integrity sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ== +javascript-stringify@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79" + integrity sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg== + jest-changed-files@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" @@ -7448,11 +7577,6 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json5@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= - json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -7535,11 +7659,6 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -klona@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" - integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== - latest-version@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" @@ -7564,47 +7683,6 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -less-loader@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-8.0.0.tgz#cd7f10e3c13ca8f71244a11ee396405ae3ce9c82" - integrity sha512-tnDs0ZdwPZgNOg0NGJ0sAD2KViG9TvOMDVibT33fH1bpLkT4xMo5Ue2FsbjFsVsUKtuRTlU0tYp2/lRizrycLg== - dependencies: - klona "^2.0.4" - -less-vars-loader@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/less-vars-loader/-/less-vars-loader-1.1.0.tgz#2f2245d9040225bfdf553fa5e0ddd8e47bca95b8" - integrity sha1-LyJF2QQCJb/fVT+l4N3Y5HvKlbg= - dependencies: - camelcase "^3.0.0" - less-vars-to-js "^1.1.2" - loader-utils "^0.2.16" - object.entries "^1.0.3" - -less-vars-to-js@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/less-vars-to-js/-/less-vars-to-js-1.3.0.tgz#c322cf43a3c8fc3fab655da3e51a14c1499ab571" - integrity sha512-xeiLLn/IMCGtdyCkYQnW8UuzoW2oYMCKg9boZRaGI58fLz5r90bNJDlqGzmVt/1Uqk75/DxIVtQSNCMkE5fRZQ== - dependencies: - strip-json-comments "^2.0.1" - -less@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/less/-/less-4.1.1.tgz#15bf253a9939791dc690888c3ff424f3e6c7edba" - integrity sha512-w09o8tZFPThBscl5d0Ggp3RcrKIouBoQscnOMgFH3n5V3kN/CXGHNfCkRPtxJk6nKryDXaV9aHLK55RXuH4sAw== - dependencies: - copy-anything "^2.0.1" - parse-node-version "^1.0.1" - tslib "^1.10.0" - optionalDependencies: - errno "^0.1.1" - graceful-fs "^4.1.2" - image-size "~0.5.0" - make-dir "^2.1.0" - mime "^1.4.1" - needle "^2.5.2" - source-map "~0.6.0" - leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -7877,16 +7955,6 @@ loader-runner@^4.2.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== -loader-utils@^0.2.16: - version "0.2.17" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" - integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g= - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - object-assign "^4.0.1" - loader-utils@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" @@ -8369,7 +8437,7 @@ mime-types@^2.1.31: dependencies: mime-db "1.49.0" -mime@1.6.0, mime@^1.4.1: +mime@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== @@ -8394,6 +8462,13 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== +mini-css-extract-plugin@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.0.tgz#578aebc7fc14d32c0ad304c2c34f08af44673f5e" + integrity sha512-ndG8nxCEnAemsg4FSgS+yNyHKgkTB4nPKqCOgh65j3/30qqC5RaSQQXMm++Y6sb6E1zRSxPkztj9fqxhS1Eo6w== + dependencies: + schema-utils "^4.0.0" + minimalistic-assert@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -8587,15 +8662,6 @@ ncp@0.4.x: resolved "https://registry.yarnpkg.com/ncp/-/ncp-0.4.2.tgz#abcc6cbd3ec2ed2a729ff6e7c1fa8f01784a8574" integrity sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ= -needle@^2.5.2: - version "2.6.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.6.0.tgz#24dbb55f2509e2324b4a99d61f413982013ccdbe" - integrity sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -8739,11 +8805,6 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - normalize-url@^5.0.0: version "5.3.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-5.3.0.tgz#8959b3cdaa295b61592c1f245dded34b117618dd" @@ -9022,7 +9083,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -9071,7 +9132,7 @@ object.assign@^4.1.0, object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" -object.entries@^1.0.3, object.entries@^1.1.2: +object.entries@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.3.tgz#c601c7f168b62374541a07ddbd3e2d5e4f7711a6" integrity sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg== @@ -9235,6 +9296,11 @@ ospath@^1.2.2: resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" integrity sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs= +outdent@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/outdent/-/outdent-0.8.0.tgz#2ebc3e77bf49912543f1008100ff8e7f44428eb0" + integrity sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A== + p-each-series@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" @@ -9463,11 +9529,6 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse-node-version@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" - integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== - parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" @@ -9653,6 +9714,13 @@ please-upgrade-node@^3.2.0: dependencies: semver-compare "^1.0.0" +polished@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/polished/-/polished-4.1.4.tgz#640293ba834109614961a700fdacbb6599fb12d0" + integrity sha512-Nq5Mbza+Auo7N3sQb1QMFaQiDO+4UexWuSGR7Cjb4Sw11SZIJcrrFtiZ+L0jT9MBsUsxDboHVASbCLbE1rnECg== + dependencies: + "@babel/runtime" "^7.16.7" + portfinder@^1.0.28: version "1.0.28" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" @@ -9667,15 +9735,6 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= -postcss-loader@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-5.2.0.tgz#ccd6668a778902d653602289c765a8bc481986dc" - integrity sha512-uSuCkENFeUaOYsKrXm0eNNgVIxc71z8RcckLMbVw473rGojFnrUeqEz6zBgXsH2q1EIzXnO/4pEz9RhALjlITA== - dependencies: - cosmiconfig "^7.0.0" - klona "^2.0.4" - semver "^7.3.4" - postcss-modules-extract-imports@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" @@ -10441,6 +10500,11 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +"require-like@>= 0.1.1": + version "0.1.2" + resolved "https://registry.yarnpkg.com/require-like/-/require-like-0.1.2.tgz#ad6f30c13becd797010c468afa775c0c0a6b47fa" + integrity sha1-rW8wwTvs15cBDEaK+ndcDAprR/o= + require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" @@ -10649,11 +10713,6 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - saxes@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" @@ -10696,6 +10755,16 @@ schema-utils@^3.1.0: ajv "^6.12.5" ajv-keywords "^3.5.2" +schema-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" + scope-eval@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/scope-eval/-/scope-eval-1.0.0.tgz#e182db1a1ef26f3e79d4bf48423b25e22839f0ff" @@ -11570,20 +11639,15 @@ strip-json-comments@3.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== -strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -style-loader@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.2.1.tgz#63cb920ec145c8669e9a50e92961452a1ef5dcde" - integrity sha512-1k9ZosJCRFaRbY6hH49JFlRB0fVSbmnyq1iTPjNxUmGVjBNEmwrrHPenhlp+Lgo51BojHSf6pl2FcqYaN3PfVg== +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= stylis@^4.0.6: version "4.0.7" @@ -11971,7 +12035,7 @@ tsconfig-paths@^3.9.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==