diff --git a/config/paths.js b/config/paths.js index 4d852d0f6..7d98ac998 100644 --- a/config/paths.js +++ b/config/paths.js @@ -53,6 +53,7 @@ module.exports = { appTsconfig: resolveApp("src/core/client/tsconfig.json"), appLocales: resolveApp("src/locales"), appThemeVariables: resolveApp("src/core/client/ui/theme/variables.ts"), + appThemeVariablesCSS: resolveApp("src/core/client/ui/theme/variables.css"), testsSetup: resolveApp("src/setupTests.js"), appNodeModules: resolveApp("node_modules"), diff --git a/config/postcss.config.js b/config/postcss.config.js index 4de2da6b2..da91c22b2 100644 --- a/config/postcss.config.js +++ b/config/postcss.config.js @@ -1,27 +1,73 @@ -const precss = require("precss"); -const autoprefixer = require("autoprefixer"); -const fontMagician = require("postcss-font-magician"); +// Allow importing typescript files. +require("ts-node/register"); + const kebabCase = require("lodash/kebabCase"); const mapKeys = require("lodash/mapKeys"); +const mapValues = require("lodash/mapValues"); +const pickBy = require("lodash/pickBy"); const flat = require("flat"); -const flexbugsFixes = require("postcss-flexbugs-fixes"); const paths = require("./paths"); +const autoprefixer = require("autoprefixer"); +const postcssFontMagician = require("postcss-font-magician"); +const postcssFlexbugsFixes = require("postcss-flexbugs-fixes"); +const postcssVariables = require("postcss-css-variables"); +const postcssPresetEnv = require("postcss-preset-env"); +const postcssNested = require("postcss-nested"); +const postcssImport = require("postcss-import"); +const postcssPrependImports = require("postcss-prepend-imports"); +const postcssAdvancedVariables = require("postcss-advanced-variables"); delete require.cache[paths.appThemeVariables]; -const variables = require(paths.appThemeVariables); +const variables = require(paths.appThemeVariables).default; const flatKebabVariables = mapKeys( - flat(variables, { delimiter: "-" }), + mapValues(flat(variables, { delimiter: "-" }), v => v.toString()), (_, k) => kebabCase(k) ); +// These are the default css standard variables. +const cssVariables = pickBy( + flatKebabVariables, + (v, k) => !k.startsWith("breakpoints-") +); + +// These are sass style variables used in media queries. +const mediaQueryVariables = mapValues( + pickBy(flatKebabVariables, (v, k) => k.startsWith("breakpoints-")), + // Add unit to breakpoints. + // Add 1 to support mobile first approach where we start + // with the smallest screen and gradually add styling for the + // next bigger screen. This is realized using `min-width` without + // ever using `max-width`. + v => `${Number.parseInt(v) + 1}px` +); + module.exports = { // Necessary for external CSS imports to work // https://github.com/facebookincubator/create-react-app/issues/2677 ident: "postcss", plugins: [ - precss({ variables: flatKebabVariables }), - fontMagician(), - flexbugsFixes, + // This allows us to define dynamic css variables. + postcssPrependImports({ + path: "", + files: [paths.appThemeVariablesCSS], + }), + // Needed by above plugin. + postcssImport(), + // Support nesting. + postcssNested(), + // Sass style variables to be used in media queries. + postcssAdvancedVariables({ variables: mediaQueryVariables }), + // CSS standard variables for everything else. + postcssVariables({ + variables: cssVariables, + }), + // Provides a modern CSS environment. + postcssPresetEnv(), + // Does all the font handling logic. + postcssFontMagician(), + // Fix known flexbox bugs. + postcssFlexbugsFixes, + // Vendor prefixing. autoprefixer({ browsers: [ ">1%", diff --git a/package-lock.json b/package-lock.json index 99ecf9b44..15875c7ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1323,16 +1323,6 @@ "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==", "dev": true }, - "@csstools/postcss-image-set-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-image-set-function/-/postcss-image-set-function-1.0.0.tgz", - "integrity": "sha512-B+uThZhN3rTRV7mjw3c+GCxIrBkHIAihnfZEb5Ig3+hauQMWGARD3j8UoMX7Hk6w4pBpMbm3Ggs9TVKvtn/kkA==", - "dev": true, - "requires": { - "postcss": "^6.0.20", - "postcss-value-parser": "^3.3.0" - } - }, "@csstools/sass-import-resolve": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@csstools/sass-import-resolve/-/sass-import-resolve-1.0.0.tgz", @@ -1857,6 +1847,15 @@ "from": "github:coralproject/patched#types/react-relay", "dev": true }, + "@types/react-responsive": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/react-responsive/-/react-responsive-3.0.1.tgz", + "integrity": "sha512-ti7MKe0AuWCGpNkRzRsRB8ExS7NZotXtDtD27rX4HiZML37SetbIp3cw5FDXIeqIC7a3TzWuPjv/I9Qcu4YL3w==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-test-renderer": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-16.0.1.tgz", @@ -6247,6 +6246,12 @@ } } }, + "css-mediaquery": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz", + "integrity": "sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA=", + "dev": true + }, "css-modules-loader-core": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz", @@ -6383,9 +6388,9 @@ "dev": true }, "cssdb": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-1.6.0.tgz", - "integrity": "sha512-KBxrzWDyY0aFA3DkAH0SDWhIKp1or83pBLqacXq4VWNrOCwf/G9An+VDXIW8qAGJz11o9nO8mQezq1ZJOdaF8A==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-3.1.0.tgz", + "integrity": "sha512-9+ASPG9O+d876YfZJjStXszOGn3EEOp5scMeCwZb/+TwTZfadQFshz/Vsh1vGET9HzaXvsfV+1O0ShFb52DddA==", "dev": true }, "cssesc": { @@ -10153,6 +10158,12 @@ "decamelize": "^1.0.0" } }, + "hyphenate-style-name": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz", + "integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es=", + "dev": true + }, "iconv-lite": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", @@ -12761,6 +12772,15 @@ "integrity": "sha1-iQwsGzv+g/sA5BKbjkz+ZFJw+dE=", "dev": true }, + "matchmediaquery": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.2.1.tgz", + "integrity": "sha1-IjxwBXk94D5HzpKxMoWnLEStos8=", + "dev": true, + "requires": { + "css-mediaquery": "^0.1.2" + } + }, "math-expression-evaluator": { "version": "1.2.17", "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", @@ -14257,92 +14277,33 @@ "postcss": "^6" } }, - "postcss-apply": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/postcss-apply/-/postcss-apply-0.9.0.tgz", - "integrity": "sha512-Ysel7CyF7FiZQno9oADqKXsfZw4DvTcQXtFvN1nLZQA3woRiVYV2M5kGJSrqQVWGjp/zqNUjUpXHs24TgxFjxg==", - "dev": true, - "requires": { - "babel-runtime": "^6.23.0", - "balanced-match": "^0.4.2", - "postcss": "^6.0.0" - }, - "dependencies": { - "balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", - "dev": true - } - } - }, - "postcss-atroot": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/postcss-atroot/-/postcss-atroot-0.1.3.tgz", - "integrity": "sha1-Z1LAIwx0UUBUk0WysOMOvtoBpAU=", - "dev": true, - "requires": { - "postcss": "^5.0.5" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "dependencies": { - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "js-base64": "^2.1.9", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" - } - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } - } - }, "postcss-attribute-case-insensitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-2.0.0.tgz", - "integrity": "sha1-lNxCLI+QmX8WvTOjZUu77AhJY7Q=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-3.0.1.tgz", + "integrity": "sha512-X/viSS9YrAoDnRa2R4sElsAmW+scOWeVW11FjWQN8m+FW1YY0jdIA9fuBSSF1pKsJTYXJXGJ1oAjFHl8cqcmKw==", "dev": true, "requires": { - "postcss": "^6.0.0", - "postcss-selector-parser": "^2.2.3" + "postcss": "^6.0.23", + "postcss-selector-parser": "^4.0.0" + }, + "dependencies": { + "cssesc": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-1.0.1.tgz", + "integrity": "sha512-S2hzrpWvE6G/rW7i7IxJfWBYn27QWfOIncUW++8Rbo1VB5zsJDSVPcnI+Q8z7rhxT6/yZeLOCja4cZnghJrNGA==", + "dev": true + }, + "postcss-selector-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-4.0.0.tgz", + "integrity": "sha512-5h+MvEjnzu1qy6MabjuoPatsGAjjDV9B24e7Cktjl+ClNtjVjmvAXjOFQr1u7RlWULKNGYaYVE4s+DIIQ4bOGA==", + "dev": true, + "requires": { + "cssesc": "^1.0.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } } }, "postcss-calc": { @@ -14406,6 +14367,16 @@ } } }, + "postcss-color-functional-notation": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-1.0.1.tgz", + "integrity": "sha512-8ECwUd75SwcjLMzFdRVRBqjVoHwGeWpLQKCNIQo9T+QeCrUNKI1NJ6rgpni5vo7iZ7MZy21qKqUieMM3D0wHYQ==", + "dev": true, + "requires": { + "postcss": "^6.0.22", + "postcss-values-parser": "^1.5.0" + } + }, "postcss-color-hex-alpha": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-3.0.0.tgz", @@ -14460,16 +14431,6 @@ "postcss-values-parser": "^1.5.0" } }, - "postcss-color-rgb": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-color-rgb/-/postcss-color-rgb-2.0.0.tgz", - "integrity": "sha1-FFOcinExSUtILg3RzCZf9lFLUmM=", - "dev": true, - "requires": { - "postcss": "^6.0.1", - "postcss-value-parser": "^3.3.0" - } - }, "postcss-colormin": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz", @@ -14591,6 +14552,17 @@ } } }, + "postcss-css-variables": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/postcss-css-variables/-/postcss-css-variables-0.9.0.tgz", + "integrity": "sha512-pSNj57bdBaFnyDzt96SZOidMMWY7Q5OySQdKsTxaxehYO6EtNC5SAKIwjah/poh5vUmNthkrlOd03bP+HNGuCA==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.3", + "extend": "^3.0.1", + "postcss": "^6.0.8" + } + }, "postcss-custom-media": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-6.0.0.tgz", @@ -14621,22 +14593,28 @@ } }, "postcss-dir-pseudo-class": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-3.0.0.tgz", - "integrity": "sha512-iEVgue59Xs6vz9CQZtlyonW/BmVfpqWglcUyIP2rQaBpH1a2T8Iax61eXY2NjTAq5r3Xjxwk4lrA84acoAiWHw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-4.0.0.tgz", + "integrity": "sha512-ZAeXMIyZukHHeDt5IFchWB+okPzasb8YnpkXIgTiJl4216X1IplMrODjihZIBDXNE2RdJRBCAOx8uGzCnGSxTA==", "dev": true, "requires": { - "postcss": "^6.0.20", - "postcss-selector-parser": "^3.1.1" + "postcss": "^6.0.22", + "postcss-selector-parser": "^4.0.0" }, "dependencies": { + "cssesc": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-1.0.1.tgz", + "integrity": "sha512-S2hzrpWvE6G/rW7i7IxJfWBYn27QWfOIncUW++8Rbo1VB5zsJDSVPcnI+Q8z7rhxT6/yZeLOCja4cZnghJrNGA==", + "dev": true + }, "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-4.0.0.tgz", + "integrity": "sha512-5h+MvEjnzu1qy6MabjuoPatsGAjjDV9B24e7Cktjl+ClNtjVjmvAXjOFQr1u7RlWULKNGYaYVE4s+DIIQ4bOGA==", "dev": true, "requires": { - "dot-prop": "^4.1.1", + "cssesc": "^1.0.1", "indexes-of": "^1.0.1", "uniq": "^1.0.1" } @@ -14939,14 +14917,14 @@ } } }, - "postcss-extend-rule": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/postcss-extend-rule/-/postcss-extend-rule-1.1.0.tgz", - "integrity": "sha512-+NXtLOY49Xcx9173SJAYj41esTRTpihSLoKpj5yzoBki9PZK4HF37AH9AVyCeLFJL9fzhh0YFuk/3eyeZ9d/jw==", + "postcss-env-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-1.0.0.tgz", + "integrity": "sha512-UVkdbVCRAEr79XkS6uxMRWIHYrFNuhXmjw6gxyesCBXzzHIvYOoz5UKTWM39xX3j9vGO5waVzxq/VzEiZgsM0g==", "dev": true, "requires": { - "postcss": "^6.0.11", - "postcss-nesting": "^4.2.1" + "postcss": "^6.0.22", + "postcss-values-parser": "^1.5.0" } }, "postcss-filter-plugins": { @@ -15018,14 +14996,23 @@ } }, "postcss-focus-visible": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-2.0.0.tgz", - "integrity": "sha512-nJaq5CK2YBWB1fu1SeK0qXAk0TJncY3Ms7iwFov+J3sNetecvTeCQuSxQCf9U9T9Vjusnb3zzThBs5XwP/eb/g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-3.0.0.tgz", + "integrity": "sha512-6i3HsOrWNelxBYPh/HWAXF9lPwCFAfFVlUTZqsLRXYMPhcXH1eXdItozRBvT9l5pYF4ddJJbgk4JOp0au0QToA==", "dev": true, "requires": { "postcss": "^6.0" } }, + "postcss-focus-within": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-2.0.0.tgz", + "integrity": "sha512-LTbT/dxZ3FahpOv1XZMyRLNnBk5QWVU4HL/p82iFkzoPNVhNQazaYIujHXTOAKea5clgjbj6GdFj7mU7qzy1kQ==", + "dev": true, + "requires": { + "postcss": "^6.0.21" + } + }, "postcss-font-family-system-ui": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-font-family-system-ui/-/postcss-font-family-system-ui-3.0.0.tgz", @@ -15056,6 +15043,37 @@ "postcss": "^6.0.1" } }, + "postcss-gap-properties": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-1.0.0.tgz", + "integrity": "sha512-snL2k0Nie72J0uCsKgfO2Sd5rs3Wlhsk+k9uVzyMaeBH9gouNPPY7tZ4bopRJmBISbZEUtvF8Gchat6nOFQHdg==", + "dev": true, + "requires": { + "postcss": "^6.0.22" + } + }, + "postcss-image-set-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-2.0.0.tgz", + "integrity": "sha512-2bpCIj2wFhIhpyM1G/ZZgBJM8K/VKbEcQ0SX5MI9MTGv4giPMnuXMa/sX3bHXHhi1PL4v2WRfqD1+w5T9EhFqg==", + "dev": true, + "requires": { + "postcss": "^6.0.22", + "postcss-values-parser": "^1.5.0" + } + }, + "postcss-import": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-11.1.0.tgz", + "integrity": "sha512-5l327iI75POonjxkXgdRCUS+AlzAdBx4pOvMEhTKTCjb1p8IEeVR9yx3cPbmN7LIWJLbfnIXxAhoB4jpD0c/Cw==", + "dev": true, + "requires": { + "postcss": "^6.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, "postcss-initial": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-2.0.0.tgz", @@ -15066,6 +15084,17 @@ "postcss": "^6.0.1" } }, + "postcss-lab-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-1.0.1.tgz", + "integrity": "sha512-kxaHXTRjlBLDpJUMsrGM0GnVgBrMqQz1HfaXdv3VNpz2EwwUhrU9uVfqv/NAtiWt6ZkD7IK2MUlncRoj024lIA==", + "dev": true, + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^6.0.22", + "postcss-values-parser": "^1.5.0" + } + }, "postcss-load-config": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", @@ -15730,15 +15759,6 @@ } } }, - "postcss-nesting": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-4.2.1.tgz", - "integrity": "sha512-IkyWXICwagCnlaviRexi7qOdwPw3+xVVjgFfGsxmztvRVaNxAlrypOIKqDE5mxY+BVxnId1rnUKBRQoNE2VDaA==", - "dev": true, - "requires": { - "postcss": "^6.0.11" - } - }, "postcss-normalize-charset": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", @@ -15920,6 +15940,15 @@ } } }, + "postcss-overflow-shorthand": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-1.0.1.tgz", + "integrity": "sha512-QeJk23W8dLP2DrWYSKTwfFfh4Tcy5Msr58vuuxCPcCijX/07jva0OGNKtUH9vZ6NnXB2WEsnfIIg5M0ScPEWeQ==", + "dev": true, + "requires": { + "postcss": "^6.0.22" + } + }, "postcss-page-break": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-1.0.0.tgz", @@ -15929,60 +15958,154 @@ "postcss": "^6.0.16" } }, - "postcss-preset-env": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-3.5.0.tgz", - "integrity": "sha512-1I7ve+XzmNLJMZDORLOjSpY28t2H1qADEUcp2tQzuLBxAsbWMBUTDpSPsCKBduoqd4zWuH4bI/04W4T4hveHQw==", + "postcss-place": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-3.0.1.tgz", + "integrity": "sha512-6Cg0z39zBU4FOS85Z6+Us+GCIW7UqKdOGH/9j26LwMzZ3L909wG7NP3BF+L12AEeIL5XfI8Q5SWu9Or3nJTS8g==", "dev": true, "requires": { - "@csstools/postcss-image-set-function": "^1.0.0", - "browserslist": "^3.2.4", - "caniuse-lite": "^1.0.30000823", - "cssdb": "^1.6.0", - "postcss": "^6.0.21", - "postcss-apply": "^0.9.0", - "postcss-attribute-case-insensitive": "^2.0.0", + "postcss": "^6.0.22", + "postcss-values-parser": "^1.5.0" + } + }, + "postcss-prepend-imports": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postcss-prepend-imports/-/postcss-prepend-imports-1.0.1.tgz", + "integrity": "sha1-v0WBiAhcM/82mVzJbJFojWSYjig=", + "dev": true, + "requires": { + "postcss": "^5.0.0" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + } + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "postcss-preset-env": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-5.2.1.tgz", + "integrity": "sha512-zsGFBKtTyCY5YxOq6Q/WR4oa9/LOKawEWMxJ7UpMtfj1t50OWeGZadRQp/i7DSSWjKus+eJKLIHDxLaobwhidQ==", + "dev": true, + "requires": { + "autoprefixer": "^8.6.3", + "browserslist": "^3.2.8", + "caniuse-lite": "^1.0.30000859", + "cssdb": "^3.1.0", + "postcss": "^6.0.23", + "postcss-attribute-case-insensitive": "^3.0.1", + "postcss-color-functional-notation": "^1.0.1", "postcss-color-hex-alpha": "^3.0.0", "postcss-color-mod-function": "^2.4.2", - "postcss-color-rebeccapurple": "^3.0.0", - "postcss-color-rgb": "^2.0.0", + "postcss-color-rebeccapurple": "^3.1.0", "postcss-custom-media": "^6.0.0", "postcss-custom-properties": "^7.0.0", "postcss-custom-selectors": "^4.0.1", - "postcss-dir-pseudo-class": "^3.0.0", - "postcss-focus-visible": "^2.0.0", + "postcss-dir-pseudo-class": "^4.0.0", + "postcss-env-function": "^1.0.0", + "postcss-focus-visible": "^3.0.0", + "postcss-focus-within": "^2.0.0", "postcss-font-family-system-ui": "^3.0.0", "postcss-font-variant": "^3.0.0", + "postcss-gap-properties": "^1.0.0", + "postcss-image-set-function": "^2.0.0", "postcss-initial": "^2.0.0", + "postcss-lab-function": "^1.0.1", "postcss-logical": "^1.1.1", "postcss-media-minmax": "^3.0.0", - "postcss-nesting": "^4.2.1", + "postcss-nesting": "^6.0.0", + "postcss-overflow-shorthand": "^1.0.1", "postcss-page-break": "^1.0.0", - "postcss-pseudo-class-any-link": "^4.0.0", + "postcss-place": "^3.0.1", + "postcss-pseudo-class-any-link": "^5.0.0", "postcss-replace-overflow-wrap": "^2.0.0", "postcss-selector-matches": "^3.0.1", "postcss-selector-not": "^3.0.1" - } - }, - "postcss-property-lookup": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-property-lookup/-/postcss-property-lookup-2.0.0.tgz", - "integrity": "sha512-KUb53a7UZWDMVb0SRODOonc4H1wlbgQ0VfYwmJaR1xWPorhariEz0U7x0ri3W/imFs6HqLYWP7hl2yMvi5Ty+w==", - "dev": true, - "requires": { - "object-assign": "^4.0.1", - "postcss": "^6.0.6", - "tcomb": "^3.2.21" + }, + "dependencies": { + "postcss-nesting": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-6.0.0.tgz", + "integrity": "sha512-Yoglsy6eZbDCbRIXoYSmnIt9ao4xyg07iFwVBd7WyIkDzMSeRxIqUk8xEAdkeJQ7eGfWo6RufrTU7FSUjZ22fg==", + "dev": true, + "requires": { + "postcss": "^6.0.22" + } + } } }, "postcss-pseudo-class-any-link": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-4.0.0.tgz", - "integrity": "sha1-kVKgYT00UHIFE+iJKFS65C0O5o4=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-5.0.0.tgz", + "integrity": "sha512-rA5grdRhLLMMI654eOZVuKGr4fUBQNGSH0K+7j5839CiBA/IvNt/Ewt7aIrkGZPySKI3nqzs34HefO8U0Fxahg==", "dev": true, "requires": { - "postcss": "^6.0.1", - "postcss-selector-parser": "^2.2.3" + "postcss": "^6.0.22", + "postcss-selector-parser": "^4.0.0" + }, + "dependencies": { + "cssesc": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-1.0.1.tgz", + "integrity": "sha512-S2hzrpWvE6G/rW7i7IxJfWBYn27QWfOIncUW++8Rbo1VB5zsJDSVPcnI+Q8z7rhxT6/yZeLOCja4cZnghJrNGA==", + "dev": true + }, + "postcss-selector-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-4.0.0.tgz", + "integrity": "sha512-5h+MvEjnzu1qy6MabjuoPatsGAjjDV9B24e7Cktjl+ClNtjVjmvAXjOFQr1u7RlWULKNGYaYVE4s+DIIQ4bOGA==", + "dev": true, + "requires": { + "cssesc": "^1.0.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } } }, "postcss-reduce-idents": { @@ -16422,21 +16545,6 @@ } } }, - "precss": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/precss/-/precss-3.1.2.tgz", - "integrity": "sha512-TAEKJjzNyKIwyDeJ3yuaTl1x0CoFw+VyycR3dO18Kl2rGU/rPNocCYH1cry1sstWwGKl3RpJhDfZ2ZdzscM0IQ==", - "dev": true, - "requires": { - "postcss": "^6.0.19", - "postcss-advanced-variables": "^2.3.3", - "postcss-atroot": "^0.1.3", - "postcss-extend-rule": "^1.1.0", - "postcss-nested": "^3.0.0", - "postcss-preset-env": "^3.2.2", - "postcss-property-lookup": "^2.0.0" - } - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -17158,6 +17266,17 @@ "prop-types": "^15.5.8" } }, + "react-responsive": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-4.1.0.tgz", + "integrity": "sha512-ZuDraf0qsJlyiTwzeva+foHx83IP6SIhru9o7BvMwQ4ZHjRIL5WjdgVNNrKSRbmeWO9rEJoMpabei/5lJn8KaA==", + "dev": true, + "requires": { + "hyphenate-style-name": "^1.0.0", + "matchmediaquery": "^0.2.1", + "prop-types": "^15.6.1" + } + }, "react-router": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz", @@ -17242,6 +17361,23 @@ "react-is": "^16.4.1" } }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -19256,12 +19392,6 @@ "integrity": "sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg==", "dev": true }, - "tcomb": { - "version": "3.2.27", - "resolved": "https://registry.npmjs.org/tcomb/-/tcomb-3.2.27.tgz", - "integrity": "sha512-XWdJW7F/M3YzXhDEUP8ycmNWoYymBtsHwCHoda0YF44RthJsls95TqDrmpAlC1sB/KXaCvkdBlcNRq+AaV6klA==", - "dev": true - }, "term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", diff --git a/package.json b/package.json index 55a3ce4ff..aa5f888b1 100644 --- a/package.json +++ b/package.json @@ -77,9 +77,9 @@ "@types/ioredis": "^3.2.8", "@types/jest": "^23.1.1", "@types/joi": "^13.0.8", + "@types/jsdom": "^11.0.6", "@types/jsonwebtoken": "^7.2.7", "@types/lodash": "^4.14.109", - "@types/jsdom": "^11.0.6", "@types/luxon": "^0.5.3", "@types/mongodb": "^3.0.19", "@types/node": "^10.3.1", @@ -90,6 +90,7 @@ "@types/query-string": "^6.1.0", "@types/react-dom": "^16.0.6", "@types/react-relay": "github:coralproject/patched#types/react-relay", + "@types/react-responsive": "^3.0.1", "@types/react-test-renderer": "^16.0.1", "@types/recompose": "^0.26.1", "@types/relay-runtime": "github:coralproject/patched#types/relay-runtime", @@ -128,10 +129,15 @@ "jsdom": "^11.11.0", "loader-utils": "^1.1.0", "npm-run-all": "^4.1.3", + "postcss-advanced-variables": "^2.3.3", + "postcss-css-variables": "^0.9.0", "postcss-flexbugs-fixes": "^3.3.1", "postcss-font-magician": "^2.2.1", + "postcss-import": "^11.1.0", "postcss-loader": "^2.1.5", - "precss": "^3.1.2", + "postcss-nested": "^3.0.0", + "postcss-prepend-imports": "^1.0.1", + "postcss-preset-env": "^5.2.1", "prettier": "^1.13.4", "query-string": "^6.1.0", "raw-loader": "^0.5.1", @@ -140,6 +146,7 @@ "react-dom": "^16.4.0", "react-final-form": "^3.6.0", "react-relay": "github:coralproject/patched#react-relay", + "react-responsive": "^4.1.0", "react-test-renderer": "^16.4.1", "recompose": "^0.27.1", "relay-compiler": "github:coralproject/patched#relay-compiler", diff --git a/src/core/client/stream/components/App.tsx b/src/core/client/stream/components/App.tsx index eb59b588e..1dd3ce496 100644 --- a/src/core/client/stream/components/App.tsx +++ b/src/core/client/stream/components/App.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { StatelessComponent } from "react"; -import { Center } from "talk-ui/components"; +import { Flex } from "talk-ui/components"; import StreamContainer from "../containers/StreamContainer"; @@ -12,9 +12,9 @@ export interface AppProps { const App: StatelessComponent = props => { if (props.asset) { return ( -
+ -
+ ); } return
Asset not found
; diff --git a/src/core/client/stream/components/Comment.css b/src/core/client/stream/components/Comment.css index c7f11300a..77dc9d88d 100644 --- a/src/core/client/stream/components/Comment.css +++ b/src/core/client/stream/components/Comment.css @@ -1,11 +1,10 @@ .root { - width: 400px; } .gutterBottom { - margin-bottom: calc(2px * $spacing-unit); + margin-bottom: calc(1px * var(--spacing-unit)); } .topBar { - margin-bottom: calc(1px * $spacing-unit); + margin-bottom: calc(0.5px * var(--spacing-unit)); } diff --git a/src/core/client/stream/components/Indent.css b/src/core/client/stream/components/Indent.css index dcf73c502..19100de68 100644 --- a/src/core/client/stream/components/Indent.css +++ b/src/core/client/stream/components/Indent.css @@ -1,8 +1,8 @@ .root { border-left: 3px solid; - padding-left: calc(2px * $spacing-unit); + padding-left: calc(1px * var(--spacing-unit)); } .level0 { - border-color: $palette-secondary-darkest; + border-color: var(--palette-secondary-darkest); } diff --git a/src/core/client/stream/components/PostCommentForm.css b/src/core/client/stream/components/PostCommentForm.css index c776ca7c8..2e9cdcc9e 100644 --- a/src/core/client/stream/components/PostCommentForm.css +++ b/src/core/client/stream/components/PostCommentForm.css @@ -3,11 +3,12 @@ display: block; height: 100px; - width: 400px; - margin-bottom: calc(2px * $spacing-unit); + width: 100%; + box-sizing: border-box; + margin-bottom: calc(1px * var(--spacing-unit)); } .postButtonContainer { display: flex; justify-content: flex-end; -} \ No newline at end of file +} diff --git a/src/core/client/stream/components/Stream.css b/src/core/client/stream/components/Stream.css new file mode 100644 index 000000000..13c90d031 --- /dev/null +++ b/src/core/client/stream/components/Stream.css @@ -0,0 +1,4 @@ +.root { + width: 100%; + max-width: 400px; +} diff --git a/src/core/client/stream/components/Stream.tsx b/src/core/client/stream/components/Stream.tsx index a14816453..f6d39940e 100644 --- a/src/core/client/stream/components/Stream.tsx +++ b/src/core/client/stream/components/Stream.tsx @@ -8,6 +8,7 @@ import CommentContainer from "../containers/CommentContainer"; import PostCommentFormContainer from "../containers/PostCommentFormContainer"; import ReplyListContainer from "../containers/ReplyListContainer"; import Logo from "./Logo"; +import * as styles from "./Stream.css"; export interface StreamProps { assetID: string; @@ -20,7 +21,7 @@ export interface StreamProps { const Stream: StatelessComponent = props => { return ( -
+
diff --git a/src/core/client/stream/components/__snapshots__/Stream.spec.tsx.snap b/src/core/client/stream/components/__snapshots__/Stream.spec.tsx.snap index 65c508b25..c529ea1ad 100644 --- a/src/core/client/stream/components/__snapshots__/Stream.spec.tsx.snap +++ b/src/core/client/stream/components/__snapshots__/Stream.spec.tsx.snap @@ -1,7 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders correctly 1`] = ` -
+
@@ -56,7 +58,9 @@ exports[`renders correctly 1`] = ` `; exports[`when there is more disables load more button 1`] = ` -
+
@@ -126,7 +130,9 @@ exports[`when there is more disables load more button 1`] = ` `; exports[`when there is more renders a load more button 1`] = ` -
+
diff --git a/src/core/client/stream/test/__snapshots__/loadMore.spec.tsx.snap b/src/core/client/stream/test/__snapshots__/loadMore.spec.tsx.snap index 8b37696d2..312540c09 100644 --- a/src/core/client/stream/test/__snapshots__/loadMore.spec.tsx.snap +++ b/src/core/client/stream/test/__snapshots__/loadMore.spec.tsx.snap @@ -2,9 +2,11 @@ exports[`loads more comments 1`] = `
-
+

@@ -111,9 +113,11 @@ exports[`loads more comments 1`] = ` exports[`renders comment stream 1`] = `
-
+

diff --git a/src/core/client/stream/test/__snapshots__/renderReplies.spec.tsx.snap b/src/core/client/stream/test/__snapshots__/renderReplies.spec.tsx.snap index 6a9e97905..2f2379935 100644 --- a/src/core/client/stream/test/__snapshots__/renderReplies.spec.tsx.snap +++ b/src/core/client/stream/test/__snapshots__/renderReplies.spec.tsx.snap @@ -2,9 +2,11 @@ exports[`renders comment stream 1`] = `
-
+

diff --git a/src/core/client/stream/test/__snapshots__/renderStream.spec.tsx.snap b/src/core/client/stream/test/__snapshots__/renderStream.spec.tsx.snap index 0090dd145..bcd18c5e2 100644 --- a/src/core/client/stream/test/__snapshots__/renderStream.spec.tsx.snap +++ b/src/core/client/stream/test/__snapshots__/renderStream.spec.tsx.snap @@ -2,9 +2,11 @@ exports[`renders comment stream 1`] = `
-
+

diff --git a/src/core/client/stream/test/__snapshots__/showAllReplies.spec.tsx.snap b/src/core/client/stream/test/__snapshots__/showAllReplies.spec.tsx.snap index 2ee40a6ae..d6e15bfca 100644 --- a/src/core/client/stream/test/__snapshots__/showAllReplies.spec.tsx.snap +++ b/src/core/client/stream/test/__snapshots__/showAllReplies.spec.tsx.snap @@ -2,9 +2,11 @@ exports[`renders comment stream 1`] = `
-
+

@@ -109,9 +111,11 @@ exports[`renders comment stream 1`] = ` exports[`show all replies 1`] = `
-
+

diff --git a/src/core/client/ui/components/Button/Button.css b/src/core/client/ui/components/Button/Button.css index 087cb0ca2..17283a819 100644 --- a/src/core/client/ui/components/Button/Button.css +++ b/src/core/client/ui/components/Button/Button.css @@ -4,7 +4,7 @@ &:enabled, &:disabled { padding: 5px 20px; - border-radius: $round-corners; + border-radius: var(--round-corners); background-color: transparent; /* TODO: hover styles for the default button */ } @@ -24,70 +24,70 @@ .primary:enabled, .primary:disabled { - background-color: $palette-primary-main; + background-color: var(--palette-primary-main); color: #fff; } .primary:enabled { &:hover { - background-color: $palette-primary-light; + background-color: var(--palette-primary-light); } &:active { - background-color: $palette-primary-lighter; + background-color: var(--palette-primary-lighter); } } .primary:enabled.invert, .primary:disabled.invert { background-color: transparent; - border: 1px solid $palette-primary-main; - color: $palette-primary-main; + border: 1px solid var(--palette-primary-main); + color: var(--palette-primary-main); } .primary:enabled.invert { &:hover { - border-color: $palette-primary-light; - color: $palette-primary-light; + border-color: var(--palette-primary-light); + color: var(--palette-primary-light); } &:active { - border-color: $palette-primary-lighter; - color: $palette-primary-lighter; + border-color: var(--palette-primary-lighter); + color: var(--palette-primary-lighter); } } .secondary:enabled, .secondary:disabled { - background-color: $palette-secondary-main; + background-color: var(--palette-secondary-main); color: #fff; } .secondary:enabled { &:hover { - background-color: $palette-secondary-light; + background-color: var(--palette-secondary-light); } &:active { - background-color: $palette-secondary-lighter; + background-color: var(--palette-secondary-lighter); } } .secondary:enabled.invert, .secondary:disabled.invert { background-color: transparent; - border: 1px solid $palette-secondary-main; - color: $palette-secondary-main; + border: 1px solid var(--palette-secondary-main); + color: var(--palette-secondary-main); } .secondary:enabled.invert { &:hover { - border-color: $palette-secondary-light; - color: $palette-secondary-light; + border-color: var(--palette-secondary-light); + color: var(--palette-secondary-light); } &:active { - border-color: $palette-secondary-lighter; - color: $palette-secondary-lighter; + border-color: var(--palette-secondary-lighter); + color: var(--palette-secondary-lighter); } } diff --git a/src/core/client/ui/components/Center/Center.css b/src/core/client/ui/components/Center/Center.css deleted file mode 100644 index 67d72755f..000000000 --- a/src/core/client/ui/components/Center/Center.css +++ /dev/null @@ -1,6 +0,0 @@ -.root { - display: flex; - align-items: center; - flex-direction: column; -} - diff --git a/src/core/client/ui/components/Center/Center.tsx b/src/core/client/ui/components/Center/Center.tsx deleted file mode 100644 index 892277ac6..000000000 --- a/src/core/client/ui/components/Center/Center.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import cn from "classnames"; -import * as React from "react"; -import { ReactNode, StatelessComponent } from "react"; - -import { withStyles } from "talk-ui/hocs"; -import { PropTypesOf } from "talk-ui/types"; - -import * as styles from "./Center.css"; - -interface InnerProps { - /** - * This prop can be used to add custom classnames. - * It is handled by the `withStyles `HOC. - */ - classes: Partial; - className?: string; - children: ReactNode; -} - -const Center: StatelessComponent = props => { - return ( -
- {props.children} -
- ); -}; - -const enhanced = withStyles(styles)(Center); -export type CenterProps = PropTypesOf; -export default enhanced; diff --git a/src/core/client/ui/components/Center/index.ts b/src/core/client/ui/components/Center/index.ts deleted file mode 100644 index 47237abf5..000000000 --- a/src/core/client/ui/components/Center/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./Center"; -export { default } from "./Center"; diff --git a/src/core/client/ui/components/Flex/Flex.css b/src/core/client/ui/components/Flex/Flex.css new file mode 100644 index 000000000..45398843b --- /dev/null +++ b/src/core/client/ui/components/Flex/Flex.css @@ -0,0 +1,51 @@ +.root { + display: flex; +} + +.justifyFlexStart { + justify-content: flex-start; +} +.justifyFlexEnd { + justify-content: flex-end; +} +.justifyCenter { + justify-content: center; +} +.justifySpaceBetween { + justify-content: space-between; +} +.justifySpaceAround { + justify-content: space-around; +} +.justifySpaceEvenly { + justify-content: space-evenly; +} + +.alignFlexStart { + align-items: flex-start; +} +.alignFlexEnd { + align-items: flex-end; +} +.alignCenter { + align-items: center; +} +.alignBaseline { + align-items: baseline; +} +.alignStretch { + align-items: stretch; +} + +.directionRow { + flex-direction: row; +} +.directionColumn { + flex-direction: column; +} +.directionRowReverse { + flex-direction: row-reverse; +} +.directionColumnReverse { + flex-direction: column-reverse; +} diff --git a/src/core/client/ui/components/Flex/Flex.mdx b/src/core/client/ui/components/Flex/Flex.mdx new file mode 100644 index 000000000..b0d8e4d23 --- /dev/null +++ b/src/core/client/ui/components/Flex/Flex.mdx @@ -0,0 +1,16 @@ +--- +name: Flex +menu: UI Kit +--- + +import { Playground, PropsTable } from 'docz' +import Flex from './Flex' + +# Flex + +`Flex` is a wrapper around `flexbox`. + +## Basic usage + + I'm centered + diff --git a/src/core/client/ui/components/Flex/Flex.spec.tsx b/src/core/client/ui/components/Flex/Flex.spec.tsx new file mode 100644 index 000000000..b774d9961 --- /dev/null +++ b/src/core/client/ui/components/Flex/Flex.spec.tsx @@ -0,0 +1,20 @@ +import { shallow } from "enzyme"; +import React from "react"; + +import { PropTypesOf } from "talk-ui/types"; + +import Flex from "./Flex"; + +it("renders correctly", () => { + const props: PropTypesOf = { + justifyContent: "center", + alignItems: "center", + direction: "row", + }; + const wrapper = shallow( + +
Hello World
+
+ ); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/src/core/client/ui/components/Flex/Flex.tsx b/src/core/client/ui/components/Flex/Flex.tsx new file mode 100644 index 000000000..3dab50168 --- /dev/null +++ b/src/core/client/ui/components/Flex/Flex.tsx @@ -0,0 +1,43 @@ +import cn from "classnames"; +import React from "react"; +import { StatelessComponent } from "react"; + +import { pascalCase } from "talk-common/utils"; + +import * as styles from "./Flex.css"; + +interface InnerProps { + justifyContent?: + | "flex-start" + | "flex-end" + | "center" + | "space-around" + | "space-between" + | "space-evenly"; + alignItems?: "flex-start" | "flex-end" | "center" | "baseline" | "stretch"; + direction?: "row" | "column" | "row-reverse" | "column-reverse"; +} + +const Flex: StatelessComponent = props => { + const { justifyContent, alignItems, direction, ...rest } = props; + + const classObject: Record = {}; + + if (justifyContent) { + classObject[(styles as any)[`justify${pascalCase(justifyContent)}`]] = true; + } + + if (alignItems) { + classObject[(styles as any)[`align${pascalCase(alignItems)}`]] = true; + } + + if (direction) { + classObject[(styles as any)[`direction${pascalCase(direction)}`]] = true; + } + + const classNames: string = cn(styles.root, classObject); + + return
; +}; + +export default Flex; diff --git a/src/core/client/ui/components/Flex/__snapshots__/Flex.spec.tsx.snap b/src/core/client/ui/components/Flex/__snapshots__/Flex.spec.tsx.snap new file mode 100644 index 000000000..90ef93c13 --- /dev/null +++ b/src/core/client/ui/components/Flex/__snapshots__/Flex.spec.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+
+ Hello World +
+
+`; diff --git a/src/core/client/ui/components/Flex/index.ts b/src/core/client/ui/components/Flex/index.ts new file mode 100644 index 000000000..27e09f37b --- /dev/null +++ b/src/core/client/ui/components/Flex/index.ts @@ -0,0 +1,2 @@ +export * from "./Flex"; +export { default } from "./Flex"; diff --git a/src/core/client/ui/components/MatchMedia/MatchMedia.mdx b/src/core/client/ui/components/MatchMedia/MatchMedia.mdx new file mode 100644 index 000000000..3f3186bb6 --- /dev/null +++ b/src/core/client/ui/components/MatchMedia/MatchMedia.mdx @@ -0,0 +1,40 @@ +--- +name: MatchMedia +menu: UI Kit +--- + +import { Playground, PropsTable } from 'docz' +import MatchMedia from './MatchMedia' + +# MatchMedia + +`MatchMedia` uses media queries to provide responsive rendering. + +## Basic usage + + + I'm a very small screen + + + I'm a small screen + + + I'm a medium screen + + + I'm a large screen + + + I'm a very large screen + + + I'm a super large screen + + + +## Using render props + + + {matches => {matches ? "I'm big" : "I'm small"}} + + diff --git a/src/core/client/ui/components/MatchMedia/MatchMedia.spec.tsx b/src/core/client/ui/components/MatchMedia/MatchMedia.spec.tsx new file mode 100644 index 000000000..3c4879015 --- /dev/null +++ b/src/core/client/ui/components/MatchMedia/MatchMedia.spec.tsx @@ -0,0 +1,27 @@ +import { shallow } from "enzyme"; +import React from "react"; + +import { PropTypesOf } from "talk-ui/types"; + +import MatchMedia from "./MatchMedia"; + +it("renders correctly", () => { + const props: PropTypesOf = { + minWidth: "xs", + maxWidth: "sm", + component: "div", + screen: true, + children:
Hello World
, + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); + +it("map new speech prop to older aural prop", () => { + const props: PropTypesOf = { + speech: true, + children:
Hello World
, + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/src/core/client/ui/components/MatchMedia/MatchMedia.tsx b/src/core/client/ui/components/MatchMedia/MatchMedia.tsx new file mode 100644 index 000000000..e7ca58f6a --- /dev/null +++ b/src/core/client/ui/components/MatchMedia/MatchMedia.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import { ReactNode, StatelessComponent } from "react"; +import Responsive from "react-responsive"; + +import theme from "../../theme/variables"; + +type Breakpoints = keyof typeof theme.breakpoints; + +interface InnerProps { + minWidth?: Breakpoints; + maxWidth?: Breakpoints; + children: ReactNode | ((matches: boolean) => React.ReactNode); + className?: string; + component?: + | string + | React.SFC + | React.ClassType + | React.ComponentClass; + all?: boolean; + print?: boolean; + screen?: boolean; + speech?: boolean; +} + +const MatchMedia: StatelessComponent = props => { + const { speech, minWidth, maxWidth, ...rest } = props; + const mapped = { + // TODO: Temporarily map newer speech to older aural type until + // react-responsive supports the speech prop. + aural: speech, + minWidth: minWidth ? theme.breakpoints[minWidth] + 1 : undefined, + maxWidth: maxWidth ? theme.breakpoints[maxWidth] : undefined, + }; + return ; +}; + +export default MatchMedia; diff --git a/src/core/client/ui/components/MatchMedia/__snapshots__/MatchMedia.spec.tsx.snap b/src/core/client/ui/components/MatchMedia/__snapshots__/MatchMedia.spec.tsx.snap new file mode 100644 index 000000000..a128d4ba0 --- /dev/null +++ b/src/core/client/ui/components/MatchMedia/__snapshots__/MatchMedia.spec.tsx.snap @@ -0,0 +1,26 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`map new speech prop to older aural prop 1`] = ` + +
+ Hello World +
+
+`; + +exports[`renders correctly 1`] = ` + +
+ Hello World +
+
+`; diff --git a/src/core/client/ui/components/MatchMedia/index.ts b/src/core/client/ui/components/MatchMedia/index.ts new file mode 100644 index 000000000..71f16f6f8 --- /dev/null +++ b/src/core/client/ui/components/MatchMedia/index.ts @@ -0,0 +1,2 @@ +export * from "./MatchMedia"; +export { default } from "./MatchMedia"; diff --git a/src/core/client/ui/components/Typography/Typography.css b/src/core/client/ui/components/Typography/Typography.css index e026c61ee..da31711e9 100644 --- a/src/core/client/ui/components/Typography/Typography.css +++ b/src/core/client/ui/components/Typography/Typography.css @@ -11,19 +11,19 @@ composes: heading2 from "talk-ui/shared/typography.css"; } -.heading3 { +.heading3 { composes: heading3 from "talk-ui/shared/typography.css"; } -.heading4 { +.heading4 { composes: heading4 from "talk-ui/shared/typography.css"; } -.subtitle1 { +.subtitle1 { composes: subtitle1 from "talk-ui/shared/typography.css"; } -.subtitle2 { +.subtitle2 { composes: subtitle2 from "talk-ui/shared/typography.css"; } @@ -31,7 +31,7 @@ composes: body1 from "talk-ui/shared/typography.css"; } -.body2 { +.body2 { composes: body2 from "talk-ui/shared/typography.css"; } @@ -70,7 +70,7 @@ } .paragraph { - margin-bottom: calc(2px * $spacing-unit); + margin-bottom: calc(1px * var(--spacing-unit)); } .colorInherit { @@ -78,17 +78,17 @@ } .colorPrimary { - color: $palette-primary-main; + color: var(--palette-primary-main); } .colorSecondary { - color: $palette-secondary-main; + color: var(--palette-secondary-main); } .colorTextSecondary { - color: $palette-text-secondary; + color: var(--palette-text-secondary); } .colorError { - color: $palette-error-main; + color: var(--palette-error-main); } diff --git a/src/core/client/ui/components/index.ts b/src/core/client/ui/components/index.ts index 54643cb2a..afca18af3 100644 --- a/src/core/client/ui/components/index.ts +++ b/src/core/client/ui/components/index.ts @@ -1,4 +1,5 @@ export { default as BaseButton } from "./BaseButton"; export { default as Button } from "./Button"; -export { default as Center } from "./Center"; export { default as Typography } from "./Typography"; +export { default as Flex } from "./Flex"; +export { default as MatchMedia } from "./MatchMedia"; diff --git a/src/core/client/ui/shared/typography.css b/src/core/client/ui/shared/typography.css index 649460503..cd94c867d 100644 --- a/src/core/client/ui/shared/typography.css +++ b/src/core/client/ui/shared/typography.css @@ -1,59 +1,63 @@ .heading1 { - font-size: calc(24rem / $rem-base); - font-weight: $font-weight-medium; + font-size: calc(24rem / var(--rem-base)); + font-weight: var(--font-weight-medium); font-family: "Manuale"; line-height: calc(32em / 24); letter-spacing: calc(0.2em / 16); - color: $palette-text-primary; + color: var(--palette-text-primary); } .heading2 { - font-size: calc(20rem / $rem-base); - font-weight: $font-weight-medium; + font-size: calc(20rem / var(--rem-base)); + font-weight: var(--font-weight-medium); font-family: "Manuale"; line-height: calc(24em / 20); - color: $palette-text-primary; + color: var(--palette-text-primary); } .heading3 { - font-size: calc(18rem / $rem-base); - font-weight: $font-weight-medium; + font-size: calc(18rem / var(--rem-base)); + font-weight: var(--font-weight-medium); font-family: "Manuale"; line-height: calc(20em / 18); letter-spacing: calc(0.2em / 16); - color: $palette-text-primary; + color: var(--palette-text-primary); } .heading4 { - font-size: calc(16rem / $rem-base); - font-weight: $font-weight-medium; + font-size: calc(16rem / var(--rem-base)); + font-weight: var(--font-weight-medium); font-family: "Manuale"; line-height: calc(18em / 16); letter-spacing: calc(0.2em / 16); - color: $palette-text-primary; + color: var(--palette-text-primary); } -.subtitle1 {} +.subtitle1 { +} -.subtitle2 {} +.subtitle2 { +} -.body2 {} +.body2 { +} .body1 { - font-size: calc(16rem / $rem-base); - font-weight: $font-weight-regular; + font-size: calc(16rem / var(--rem-base)); + font-weight: var(--font-weight-regular); font-family: "Source Sans Pro"; line-height: calc(18em / 16); letter-spacing: calc(0.2em / 16); - color: $palette-text-primary; + color: var(--palette-text-primary); } .button { - color: $palette-text-secondary; + color: var(--palette-text-secondary); font-family: "Source Sans Pro"; - font-weight: $font-weight-medium; + font-weight: var(--font-weight-medium); font-size: 16px; letter-spacing: calc(0.57em / 16); } -.overline {} +.overline { +} diff --git a/src/core/client/ui/theme/variables.css b/src/core/client/ui/theme/variables.css new file mode 100644 index 000000000..687417bf4 --- /dev/null +++ b/src/core/client/ui/theme/variables.css @@ -0,0 +1,16 @@ +/* + Variables defined in `variables.ts` are already available + flattened and in kebab case. + + These are additionally variables we define. +*/ + +:root { + --spacing-unit: var(--spacing-unit-small); +} + +@media (min-width: $breakpoints-xs) { + :root { + --spacing-unit: var(--spacing-unit-large); + } +} diff --git a/src/core/client/ui/theme/variables.ts b/src/core/client/ui/theme/variables.ts index 4c4a54332..d68b88a41 100644 --- a/src/core/client/ui/theme/variables.ts +++ b/src/core/client/ui/theme/variables.ts @@ -58,7 +58,8 @@ const variables = { }, }, /* gitter and spacing */ - spacingUnit: 5, + spacingUnitSmall: 5, + spacingUnitLarge: 10, /* Borders */ roundCorners: "2px", /* Typography */ @@ -68,6 +69,14 @@ const variables = { fontWeightLight: 300, fontWeightRegular: 400, fontWeightMedium: 550, + /* Breakpoints */ + breakpoints: { + xs: 320, + sm: 640, + md: 1024, + lg: 1400, + xl: 1600, + }, }; -module.exports = variables; +export default variables; diff --git a/src/core/common/utils/index.ts b/src/core/common/utils/index.ts index 88c1f3fec..e91489017 100644 --- a/src/core/common/utils/index.ts +++ b/src/core/common/utils/index.ts @@ -1 +1,2 @@ export { default as timeout } from "./timeout"; +export { default as pascalCase } from "./pascalCase"; diff --git a/src/core/common/utils/pascalCase.ts b/src/core/common/utils/pascalCase.ts new file mode 100644 index 000000000..de0bbace8 --- /dev/null +++ b/src/core/common/utils/pascalCase.ts @@ -0,0 +1,5 @@ +import { camelCase } from "lodash"; + +export default function pascalCase(value: string) { + return value[0].toUpperCase() + camelCase(value).slice(1); +} diff --git a/src/locales/es/common.ftl b/src/locales/es/common.ftl new file mode 100644 index 000000000..e69de29bb