diff --git a/CHANGELOG.md b/CHANGELOG.md index 8170c8ef..11653bdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,16 @@ Future Todo List - Make typography and utility classes silent extenders (so that they can be extended by components without importing all utility classes). - Deprecate modal and orderCard component styles in next major version as unused. +v8.1.0 +------------------------------ +*May 12, 2022* + +### Added +- f-utils `functions`, `helpers` & `mixins` in order to depreciate `f-utils` in favour of `fozzie`. + +### Removed +- f-utils dependency. + v8.0.0 ------------------------------ diff --git a/package.json b/package.json index e9c8b18a..469c8250 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@justeat/fozzie", "title": "Fozzie – Just Eat UI Web Framework", "description": "UI Web Framework for the Just Eat Global Platform", - "version": "8.0.0", + "version": "8.1.0", "main": "dist/js/index.js", "files": [ "dist/js", @@ -30,10 +30,9 @@ }, "license": "Apache-2.0", "engines": { - "node": ">=10.0.0" + "node": "^12 || ^14" }, "dependencies": { - "@justeat/f-utils": "3.5.0", "@justeat/pie-design-tokens": "1.4.0", "include-media": "1.4.10" }, diff --git a/src/scss/_dependencies.scss b/src/scss/_dependencies.scss index d9648eab..1808a125 100644 --- a/src/scss/_dependencies.scss +++ b/src/scss/_dependencies.scss @@ -15,7 +15,7 @@ // See mixins/css3.scss for the full list // Including helper modules -@import '@justeat/f-utils/src/scss/'; // imports Fozzie SCSS helper functions and mixins – https://github.com/justeat/f-utils +@import 'tools/index'; // imports Fozzie SCSS helper functions and mixins @import 'include-media/dist/_include-media'; // Cleaner media query declarations – http://include-media.com @@ -26,7 +26,7 @@ @import '@justeat/pie-design-tokens/dist/jet'; @import 'settings/variables'; -@import '@justeat/f-utils/src/scss/helpers/breakpoints'; // breakpoint helper – https://github.com/justeat/f-utils/blob/96508ae19809c4b8b83cebb55b9d74728d01c1a5/src/scss/helpers/_breakpoints.scss +@import 'tools/helpers/breakpoints'; // breakpoint helper - @TODO move to the `templates.scss` file as part of the next major version bump. // CSS Normalise and then Reset diff --git a/src/scss/tools/_index.scss b/src/scss/tools/_index.scss index db3087b0..4ee87553 100644 --- a/src/scss/tools/_index.scss +++ b/src/scss/tools/_index.scss @@ -1,12 +1,12 @@ // ================================= // Tools // ================================= +// Sass utility functions and mixins for the Fozzie framework // -// Fozzie utilities such as mixins and functions are defined -// in the f-utils module. +// Importing the base module using eyeglass will import all mixins and functions // -// Repo: https://github.com/justeat/f-utils -// NPM Module: https://www.npmjs.com/package/@justeat/f-utils -// -// Any project specific mixins and functions should be created in a folder -// called 'tools' like this file. +// In addition you can import optional helpers such as breakpoints and code-highlighting such as: +// @import '/helpers/breakpoints' + +@import 'mixins'; +@import 'functions'; diff --git a/src/scss/tools/functions/_index.scss b/src/scss/tools/functions/_index.scss new file mode 100644 index 00000000..17fdbb96 --- /dev/null +++ b/src/scss/tools/functions/_index.scss @@ -0,0 +1,12 @@ +// ========================================================================== +// Function imports +// +// N.b. Remember to use comments starting with // in these files so that they +// don’t get compiled into CSS (as mixins aren’t compiled directly) +// ========================================================================== + +@import 'px-to-em'; +@import 'spacing'; +@import 'strip-units'; +@import 'units'; +@import 'zIndex'; diff --git a/src/scss/tools/functions/_px-to-em.scss b/src/scss/tools/functions/_px-to-em.scss new file mode 100755 index 00000000..31731b81 --- /dev/null +++ b/src/scss/tools/functions/_px-to-em.scss @@ -0,0 +1,40 @@ +/** + * px to em converter + * ================================= + * Convert pixels to ems + * + * Usage: + * font-size : em(12); + * font-size : em(12, 24); // If the parent is another value say 24px + */ + +@use 'sass:math'; + +@function em($pxval, $base: $font-size-base) { + @return math.div($pxval, $base) * 1em; +} + +/** + * Convert a map of breakpoints to ems + * ================================= + * Takes a map of breakpoints (in px) and a base-font-size + * + * Usage: + $breakpoints: map-to-em(( + narrow : 400px, + mid : 750px, + wide : 1000px, + huge : 1250px + ), 16); + */ + +@function map-to-em($breakpoints, $base: $font-size-base) { + $newBreakpoints: (); + + @each $name, $pxValue in $breakpoints { + $emValue: em(strip-units($pxValue), $base); + $newBreakpoints: map-merge($newBreakpoints, ($name: $emValue)); + } + + @return $newBreakpoints; +} diff --git a/src/scss/tools/functions/_spacing.scss b/src/scss/tools/functions/_spacing.scss new file mode 100644 index 00000000..036169ef --- /dev/null +++ b/src/scss/tools/functions/_spacing.scss @@ -0,0 +1,28 @@ +// ========================================================================== +// _spacing.scss +// +// Contains all functions relating to spacing +// ========================================================================== + +// +// spacing() +// +// Allows developers to specify the amount of spacing they require via shortcut +// Accesses the spacing map definition in _variables.scss +// +// Usage: +// spacing() or +// spacing(b) +// +// Key can be passed in as = a, b, c, d, e, f, g, h, i, j +// ========================================================================== +@function spacing($key: 'b') { + @if type-of($spacing) == 'map' { + @if map-has-key($spacing, $key) { + @return map-get($spacing, $key); + } + } + + @warn 'Unknown `#{$key}` in $spacing.'; + @return null; +} diff --git a/src/scss/tools/functions/_strip-units.scss b/src/scss/tools/functions/_strip-units.scss new file mode 100644 index 00000000..e683dd23 --- /dev/null +++ b/src/scss/tools/functions/_strip-units.scss @@ -0,0 +1,22 @@ +/** + * Strip units + * ================================= + * Remove the unit of a measurement + * + * Usage: + * strip-units(400px) > 400 + */ + +@use 'sass:math'; + +@function strip-units($val) { + $newVal: 0; + + @if $val { + $newVal: $val; + } @else { + $newVal: 0; + } + + @return math.div($newVal, $newVal * 0 + 1); +} diff --git a/src/scss/tools/functions/_units.scss b/src/scss/tools/functions/_units.scss new file mode 100644 index 00000000..fb295fb6 --- /dev/null +++ b/src/scss/tools/functions/_units.scss @@ -0,0 +1,78 @@ +// ========================================================================== +// _units.scss +// +// Contains all functions relating to units +// ========================================================================== + +// @include line-height +// +// Given a font-size and a line-height (in pixels) +// Returns a unitless line-height value +// +@use 'sass:math'; + +@function line-height($font-size: 'body-s', $line-height: '20', $scale: 'default') { + @if type-of($font-size) == 'number' { + @return decimal-round(math.div($line-height, $font-size), 2); + } @else if map-has-key($type, $font-size) { // else try and find the value in our type map + $key-map: map-get($type, $font-size); + $font-list: map-get($key-map, $scale); + + @if type-of($font-list) == 'list' { + @return line-height(nth($font-list, 1), nth($font-list, 2)); + } @else { + @warn 'No line-height found as part of the $type map for #{ $font-size }'; + } + } +} + +@function decimal-round($number, $digits: 0, $mode: round) { + $n: 1; + + // $number must be a number + @if type-of($number) != number { + @warn '#{ $number } is not a number.'; + @return $number; + } + + // $digits must be a unitless number + @if type-of($digits) != number { + @warn '#{ $digits } is not a number.'; + @return $number; + } @else if not unitless($digits) { + @warn '#{ $digits } has a unit.'; + @return $number; + } + + @if $digits > 0 { + @for $i from 1 through $digits { + $n: $n * 10; + } + } + + @if $mode == round { + @return math.div(round($number * $n), $n); + } @else if $mode == ceil { + @return math.div(ceil($number * $n), $n); + } @else if $mode == floor { + @return math.div(floor($number * $n), $n); + } @else { + @warn '#{ $mode } is undefined keyword.'; + @return $number; + } +} + +@function em-to-px($emVal, $base: $font-size-base) { + @return ($emVal * $base) * 1px; +} + +@function map-to-px($breakpoints, $base: $font-size-base) { + $newBreakpoints: (); + + @each $name, $emValue in $breakpoints { + $pxValue: em-to-px(strip-units($emValue), $base); + $newBreakpoints: map-merge($newBreakpoints, ($name: $pxValue)); + } + + @return $newBreakpoints; +} diff --git a/src/scss/tools/functions/_zIndex.scss b/src/scss/tools/functions/_zIndex.scss new file mode 100644 index 00000000..ec8cf9df --- /dev/null +++ b/src/scss/tools/functions/_zIndex.scss @@ -0,0 +1,27 @@ +// ========================================================================== +// _zIndex.scss +// +// Contains all functions relating to zIndex +// ========================================================================== + +// +// zIndex() +// +// Allows developers to specify the amount of zIndex they require via shortcut +// Accesses the spacing map definition in _variables.scss +// +// Usage: +// zIndex(low) +// +// Key can be passed in as = lowest, low, medium, high +// ========================================================================== +@function zIndex($key: 'lowest') { + @if type-of($zIndex) == 'map' { + @if map-has-key($zIndex, $key) { + @return map-get($zIndex, $key); + } + } + + @warn 'Unknown `#{$key}` in $zIndex.'; + @return null; +} diff --git a/src/scss/tools/helpers/_breakpoints.scss b/src/scss/tools/helpers/_breakpoints.scss new file mode 100644 index 00000000..d8d87c13 --- /dev/null +++ b/src/scss/tools/helpers/_breakpoints.scss @@ -0,0 +1,15 @@ +@function populate-breakpoints() { + $breakpointString: ''; + $breakpointsPx: map-to-px($breakpoints, 16); + + @each $name, $value in $breakpointsPx { + $breakpointString: $breakpointString + '#{$name}:#{$value},'; + } + + @return str-slice($breakpointString, 0, str-length($breakpointString) - 1); +} + +.c-screen-sizer { + display: none; + content: populate-breakpoints(); +} diff --git a/src/scss/tools/helpers/_code-highlighting.scss b/src/scss/tools/helpers/_code-highlighting.scss new file mode 100644 index 00000000..fda4fa92 --- /dev/null +++ b/src/scss/tools/helpers/_code-highlighting.scss @@ -0,0 +1,189 @@ +/** + * Code Highlighting + * =================================== + */ + +/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+scss */ + +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ + +code[class*='language-'], +pre[class*='language-'] { + color: black; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + direction: ltr; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + line-height: 1.5; + tab-size: 4; + hyphens: none; +} + +pre[class*='language-']::selection, +pre[class*='language-'] ::selection, +code[class*='language-']::selection, +code[class*='language-'] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: spacing(d) 0; + overflow: auto; +} + +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #a67f59; + background: hsl(0deg 0% 100% / 50%); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function { + color: #dd4a68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/** + * Define associated Code variables + */ +$code-textColor: #444; +$code-bgColor: #f9f8f8; +$pre-textColor: #444; +$pre-bgColor: #f9f8f8; + +// Inline and block code styles +code, +pre { + border: 1px solid #ddd; + padding: 10px; + font-family: $font-family-mono; + + @include font-size(small, false); + + color: $code-textColor; + tab-size: 3; + overflow: auto; +} + +// Inline code +code { + padding: 2px 4px; + color: $code-textColor; + background-color: $code-bgColor; +} + +// Blocks of code +pre { + display: block; + padding: floor($spacing(d) / 2); + margin: spacing(d) 0; + color: $pre-textColor; + background-color: $pre-bgColor; + white-space: pre; + + // white-space: pre-wrap; + // word-break: break-all; + // word-wrap: break-word; + + // Account for some code outputs that place code tags in pre tags + code { + padding: 0; + color: $pre-textColor; + background-color: inherit; + border: 0; + } +} + +// Enable scrollable blocks of code +.pre--scrollable { + max-height: 340px; + overflow-y: scroll; +} diff --git a/src/scss/tools/mixins/_alerts.scss b/src/scss/tools/mixins/_alerts.scss new file mode 100644 index 00000000..d1850309 --- /dev/null +++ b/src/scss/tools/mixins/_alerts.scss @@ -0,0 +1,11 @@ +// +// ========================================================================== +// Alert variant mixin +// Used in alert modifier classes to colorize the alert +// ========================================================================== +// +@mixin alert-variant($color-primary, $color-text) { + background-color: $color-primary; + border-color: darken($color-primary, 10%); + color: $color-text; +} diff --git a/src/scss/tools/mixins/_border.scss b/src/scss/tools/mixins/_border.scss new file mode 100644 index 00000000..c0727ce8 --- /dev/null +++ b/src/scss/tools/mixins/_border.scss @@ -0,0 +1,18 @@ +// +// ========================================================================== +// Border mixin +// Used in bordered utility class to add padding, border and border +// radius to element +// ========================================================================== +// +// Standard use +// @include bordered(); +// +// Override default values +// @include bordered(10px, 30px, green); + +@mixin bordered($bordered-radius: $border-radius, $bordered-spacing : spacing(e), $bordered-colour: $color-border-strong) { // stylelint-disable-line max-line-length + border: 1px solid $bordered-colour; + padding: $bordered-spacing; + border-radius: $bordered-radius; +} diff --git a/src/scss/tools/mixins/_index.scss b/src/scss/tools/mixins/_index.scss new file mode 100644 index 00000000..b4af4381 --- /dev/null +++ b/src/scss/tools/mixins/_index.scss @@ -0,0 +1,11 @@ +// ========================================================================== +// Mixin imports +// +// N.b. Remember to use comments starting with // in these files so that they +// don’t get compiled into CSS (as mixins aren’t compiled directly) +// ========================================================================== +@import 'type'; +@import 'truncate'; +@import 'alerts'; +@import 'ratings'; +@import 'border'; diff --git a/src/scss/tools/mixins/_ratings.scss b/src/scss/tools/mixins/_ratings.scss new file mode 100644 index 00000000..c0efdf09 --- /dev/null +++ b/src/scss/tools/mixins/_ratings.scss @@ -0,0 +1,49 @@ +// +// ========================================================================== +// Ratings variant mixin +// Used in rating modify to fill the star ratings +// ========================================================================== +// +// eg. example of generated fill classes for a 3 star rating +// +// .c-ratings--fill-30 { +// width: 50%; +// } +// +// 5 star rating +// +// .c-ratings--fill-50 { +// width: 83.33%; +// } + +@use 'sass:math'; + +$rating-iterations: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + +@mixin rating-fill($maxStars: 6) { + @if $maxStars > 0 { + @for $i from 0 to $maxStars + 1 { + @if $i < $maxStars { + @each $ratingIteration in $rating-iterations { + /* stylelint-disable max-nesting-depth */ + @if $i == 0 and $ratingIteration == 0 { + &.c-ratings--fill-00 { + width: 0; + } + } @else { + &.c-ratings--fill-#{$i}#{$ratingIteration} { + width: math.div(($ratingIteration * 0.1) + $i, $maxStars) * 100%; + } + } + /* stylelint-enable max-nesting-depth */ + } + } @else { + &.c-ratings--fill-#{$i}#{0} { + width: math.div($i, $maxStars) * 100%; + } + } + } + } @else { + @warn 'Max star count must be greater than 0'; + } +} diff --git a/src/scss/tools/mixins/_truncate.scss b/src/scss/tools/mixins/_truncate.scss new file mode 100644 index 00000000..fbfa5ccb --- /dev/null +++ b/src/scss/tools/mixins/_truncate.scss @@ -0,0 +1,13 @@ +// +// ========================================================================== +// Truncate mixin +// Forces overly long spans of text to truncate +// ========================================================================== +// +// @include truncate(truncation-boundary); +@mixin truncate($truncation-boundary: null) { + max-width: $truncation-boundary; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/src/scss/tools/mixins/_type.scss b/src/scss/tools/mixins/_type.scss new file mode 100644 index 00000000..7e145a72 --- /dev/null +++ b/src/scss/tools/mixins/_type.scss @@ -0,0 +1,62 @@ +// ========================================================================== +// Typography mixins +// ========================================================================== + +// REM +// @include rem(margin, $font-size-base); +@use 'sass:math'; + +@mixin rem($property, $sizeValue: $font-size-base) { + $unitlessSizeValue: strip-units($sizeValue); + $remValue: math.div($unitlessSizeValue, $font-size-base); + + #{$property}: ceil($unitlessSizeValue) + px; + #{$property}: $remValue + rem; +} + +// EM +// @include em(margin, $font-size-base); +@mixin em($property, $sizeValue: $font-size-base) { + #{$property}: math.div(strip-units($sizeValue), $font-size-base) + em; +} + +@mixin font-size($key: 'body-s', $line-height: true, $scale: 'default', $relativeToParent: false) { + // if the $key passed in is actually just a font-size + // then output it (may want to instead force a sass error saying to use the type map?) + @if type-of($key) == 'number' { + @if $relativeToParent == true { + @include em(font-size, $key); + } @else { + @include rem(font-size, $key); + } + } @else if map-has-key($type, $key) { // else try and find the value in our type map + $key-map: map-get($type, $key); + $font-list: map-get($key-map, $scale); + + // If $size-map is a list, include + // both font-size and line-height + @if type-of($font-list) == 'list' { + $font-size: nth($font-list, 1); + + @if $relativeToParent == true { + @include em(font-size, $font-size); + } @else { + @include rem(font-size, $font-size); + } + + @if length($font-list) > 1 and $line-height == true { + $line-height: nth($font-list, 2); + + line-height: line-height($font-size, $line-height); + } + } @else { + @if $relativeToParent == true { + @include em(font-size, $font-list); + } @else { + @include rem(font-size, $font-list); + } + } + } @else { + @warn 'Unknown `#{$key}` in $type.'; + } +}