From b4f2eae609c5bdfe045480541443e865bc373091 Mon Sep 17 00:00:00 2001 From: Vince Picone Date: Tue, 30 Jul 2019 14:30:34 -0500 Subject: [PATCH] chore: migrate type component --- gatsby-config.js | 4 - package.json | 2 + src/components/TypesetStyle/InputRange.js | 37 + .../TypesetStyle/StickyContainer.js | 46 + src/components/TypesetStyle/TypesetExample.js | 177 ++++ src/components/TypesetStyle/TypesetStyle.js | 946 ++++++++++++++++++ src/components/TypesetStyle/index.js | 3 + .../TypesetStyle/typeset-style.scss | 459 +++++++++ .../guidelines/typography/expressive.mdx | 2 +- .../guidelines/typography/productive.mdx | 2 +- yarn.lock | 2 +- 11 files changed, 1673 insertions(+), 7 deletions(-) create mode 100644 src/components/TypesetStyle/InputRange.js create mode 100644 src/components/TypesetStyle/StickyContainer.js create mode 100644 src/components/TypesetStyle/TypesetExample.js create mode 100644 src/components/TypesetStyle/TypesetStyle.js create mode 100644 src/components/TypesetStyle/index.js create mode 100644 src/components/TypesetStyle/typeset-style.scss diff --git a/gatsby-config.js b/gatsby-config.js index 7631e999172..ecc4baff059 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -15,9 +15,5 @@ module.exports = { }, }, }, - { - resolve: 'gatsby-plugin-compile-es6-packages', - options: { modules: ['@carbon/addons-website'] }, - }, ], }; diff --git a/package.json b/package.json index a7f796649f4..fe5d2c86f2c 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "format": "prettier --write 'src/**/*.{js,json,css,scss,md,mdx,yaml}'" }, "dependencies": { + "@carbon/elements": "^10.4.0", "@carbon/icons-react": "^10.4.1", "@reach/router": "^1.2.1", "carbon-components": "^10.4.1", @@ -21,6 +22,7 @@ "gatsby-plugin-compile-es6-packages": "^2.1.0", "gatsby-theme-carbon": "^1.6.2", "html-loader": "^0.5.5", + "lodash": "^4.17.15", "markdown-it": "^9.0.1", "markdown-loader": "^5.0.0", "prismjs": "^1.17.1", diff --git a/src/components/TypesetStyle/InputRange.js b/src/components/TypesetStyle/InputRange.js new file mode 100644 index 00000000000..ab04cdc409f --- /dev/null +++ b/src/components/TypesetStyle/InputRange.js @@ -0,0 +1,37 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { settings } from 'carbon-components'; + +const { prefix } = settings; + +const InputRange = ({ step, min, max, value, onChange }) => ( + +); + +InputRange.propTypes = { + // input step + step: PropTypes.number, + + // input min + min: PropTypes.number.isRequired, + + // input max + max: PropTypes.number.isRequired, + + // input value + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + + // onChange function + onChange: PropTypes.func.isRequired, +}; + +export default InputRange; diff --git a/src/components/TypesetStyle/StickyContainer.js b/src/components/TypesetStyle/StickyContainer.js new file mode 100644 index 00000000000..ddf73585053 --- /dev/null +++ b/src/components/TypesetStyle/StickyContainer.js @@ -0,0 +1,46 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { settings } from 'carbon-components'; +import classnames from 'classnames'; + +const { prefix } = settings; + +const StickyContainer = ({ + children, + banner, + navBar, + secondary, + top, + className, +}) => { + const stickyClass = classnames(`${prefix}--sticky-container`, className, { + [`${prefix}--sticky-container-banner`]: banner, + [`${prefix}--sticky-container-visible`]: navBar, + [`${prefix}--sticky-container-hidden`]: !navBar, + [`${prefix}--sticky-container-secondary`]: secondary, + [`${prefix}--sticky-container-secondary-visible`]: navBar && secondary, + [`${prefix}--sticky-container-secondary-hidden`]: !navBar && secondary, + }); + + return ( +
+ {children} +
+ ); +}; + +StickyContainer.propTypes = { + // if site has banner at top ( ex. go to v1) + banner: PropTypes.bool, + + // if page navBar is showing / hiding, toggle this on/off + navBar: PropTypes.bool, + + // for items that are on pages that already have a sticky item + secondary: PropTypes.bool, + + // if custom top is necessary, must include units - (rem, px) + top: PropTypes.string, +}; + +export default StickyContainer; diff --git a/src/components/TypesetStyle/TypesetExample.js b/src/components/TypesetStyle/TypesetExample.js new file mode 100644 index 00000000000..a1a733c8731 --- /dev/null +++ b/src/components/TypesetStyle/TypesetExample.js @@ -0,0 +1,177 @@ +import React from 'react'; +import { settings } from 'carbon-components'; +import classnames from 'classnames'; +import { findKey, values } from 'lodash'; +import { + baseFontSize, + breakpoints as carbonBreakpoints, +} from '@carbon/elements'; +import { CodeSnippet } from 'carbon-components-react'; + +const { prefix } = settings; + +const breakpoints = { + sm: Number(carbonBreakpoints.sm.width.replace('rem', '')) * baseFontSize, + md: Number(carbonBreakpoints.md.width.replace('rem', '')) * baseFontSize, + lg: Number(carbonBreakpoints.lg.width.replace('rem', '')) * baseFontSize, + xlg: Number(carbonBreakpoints.xlg.width.replace('rem', '')) * baseFontSize, + max: Number(carbonBreakpoints.max.width.replace('rem', '')) * baseFontSize, +}; + +const defaultTypeValues = { + 'letter-spacing': 0, +}; + +const TypesetExample = props => ( +
+ {(props.typeSet || []).map(type => { + const indexOfClosestLargerBreakpoint = Math.max( + 0, + values(breakpoints).findIndex( + width => props.simulatedScreenWidth <= width + ) + ); + + const currentBreakpointPx = values(breakpoints)[ + indexOfClosestLargerBreakpoint + ]; + + const currentBreakpointName = findKey( + breakpoints, + val => val === currentBreakpointPx + ); + const getCurrentCompoundStylesForBreakpoint = breakpointName => { + const typeKeys = Object.keys(breakpoints); + const typeStylesUntilCurrentBreakpoint = []; + // eslint-disable-next-line no-restricted-syntax + for (const item of typeKeys) { + typeStylesUntilCurrentBreakpoint.push( + props.typeScale[type.key][item] + ); + if (item === breakpointName) break; + } + return Object.assign( + {}, + defaultTypeValues, + ...typeStylesUntilCurrentBreakpoint + ); + }; + + const currentBreakpointSpecs = getCurrentCompoundStylesForBreakpoint( + currentBreakpointName + ); + + const calculateFluidTypeSize = attribute => + currentBreakpointSpecs[attribute] * baseFontSize; + + const calculateFluidLineHeight = attribute => + currentBreakpointSpecs[attribute] * baseFontSize; + + const displayWeight = (weight, style) => { + if (style === 'italic') { + return `${weight} / Italic`; + } + switch (weight) { + case '300': + return '300 / Light'; + case '400': + return '400 / Regular'; + case '600': + return '600 / Semi-Bold'; + default: + return weight; + } + }; + + const specs = { + fontWeight: currentBreakpointSpecs['font-weight'], + fontSize: `${calculateFluidTypeSize('font-size')}px`, + fontStyle: currentBreakpointSpecs['font-style'], + lineHeight: `${calculateFluidLineHeight('line-height')}px`, + letterSpacing: currentBreakpointSpecs['letter-spacing'], + }; + const displaySpecs = { + step: currentBreakpointSpecs.step, + font: currentBreakpointSpecs.font, + style: currentBreakpointSpecs['font-style'], + fontWeight: displayWeight( + currentBreakpointSpecs['font-weight'], + currentBreakpointSpecs['font-style'] + ), + fontSize: `${`${calculateFluidTypeSize('font-size')}px` + + ' / '}${currentBreakpointSpecs['font-size'] + .toString() + .replace('0.', '.')}rem`, + // eslint-disable-next-line no-useless-concat + lineHeight: `${`${calculateFluidLineHeight('line-height')}px` + ` / `}${ + currentBreakpointSpecs['line-height'] + }rem`, + letterSpacing: currentBreakpointSpecs['letter-spacing'] + .toString() + .replace('0.', '.'), + warning: currentBreakpointSpecs.warning, + }; + + const versionClassName = type.version + ? `${prefix}--type-${type.version}` + : ''; + + const versionClassNames = classnames( + `${prefix}--type-${type.key}`, + versionClassName + ); + + return ( +
+
+
+

+ {type.description} +

+
+
+ + {type.name} +
+ Type: {displaySpecs.font} +
+ Size: {displaySpecs.fontSize} +
+ Line-height: {displaySpecs.lineHeight} +
+ Weight:{' '} + + {displaySpecs.fontWeight} + +
+ Letter-spacing: {displaySpecs.letterSpacing}px + {displaySpecs.warning != null ? ( + +
+ + warning:{' '} + + {displaySpecs.warning} +
+
+ ) : ( +
+ )} +
+ ${type.name} +
+
+
+
+
+ ); + })} +
+); + +export default TypesetExample; diff --git a/src/components/TypesetStyle/TypesetStyle.js b/src/components/TypesetStyle/TypesetStyle.js new file mode 100644 index 00000000000..087d50bab9a --- /dev/null +++ b/src/components/TypesetStyle/TypesetStyle.js @@ -0,0 +1,946 @@ +/* eslint-disable react/no-string-refs */ +import React from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import { settings } from 'carbon-components'; +import { + baseFontSize, + breakpoints as carbonBreakpoints, +} from '@carbon/elements'; +import { findLastIndex, values } from 'lodash'; + +import InputRange from './InputRange'; +import StickyContainer from './StickyContainer'; +import TypesetExample from './TypesetExample'; + +const { prefix } = settings; + +const typeScale = { + 'caption-01': { + sm: { + step: 1, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 0.75, + 'line-height': 1, + 'letter-spacing': 0.32, + }, + }, + 'label-01': { + sm: { + step: 1, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 0.75, + 'line-height': 1, + 'letter-spacing': 0.32, + }, + }, + 'helper-text-01': { + sm: { + step: 1, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-style': 'italic', + 'font-size': 0.75, + 'line-height': 1, + 'letter-spacing': 0.32, + }, + }, + + 'body-short-01': { + sm: { + step: 2, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 0.875, + 'line-height': 1.125, + 'letter-spacing': 0.16, + }, + }, + 'body-short-02': { + sm: { + step: 3, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 1, + 'line-height': 1.375, + 'letter-spacing': 0, + }, + }, + 'body-long-01': { + sm: { + step: 2, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 0.875, + 'line-height': 1.25, + 'letter-spacing': 0.16, + }, + }, + 'body-long-02': { + sm: { + step: 3, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 1, + 'line-height': 1.5, + 'letter-spacing': 0, + }, + }, + 'code-01': { + sm: { + step: 1, + font: 'IBM Plex Mono', + 'font-weight': '400', + 'font-size': 0.75, + 'line-height': 1, + 'letter-spacing': 0.32, + }, + }, + 'code-02': { + sm: { + step: 1, + font: 'IBM Plex Mono', + 'font-weight': '400', + 'font-size': 0.875, + 'line-height': 1.25, + 'letter-spacing': 0.32, + }, + }, + 'heading-01': { + sm: { + step: 2, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 0.875, + 'line-height': 1.125, + 'letter-spacing': 0.16, + }, + }, + 'heading-02': { + sm: { + step: 3, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 1, + 'line-height': 1.375, + 'letter-spacing': 0, + }, + }, + 'productive-heading-03': { + sm: { + step: 3, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 1.25, + 'line-height': 1.625, + 'letter-spacing': '0', + }, + }, + 'productive-heading-04': { + sm: { + step: 7, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 1.75, + 'line-height': 2.25, + 'letter-spacing': '0', + }, + }, + 'productive-heading-05': { + sm: { + step: 8, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 2, + 'line-height': 2.5, + 'letter-spacing': '0', + }, + }, + + 'expressive-heading-04': { + sm: { + step: 7, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 1.75, + 'line-height': 2.25, + 'letter-spacing': '0', + }, + md: { + step: 7, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 1.75, + 'line-height': 2.25, + 'letter-spacing': '0', + }, + lg: { + step: 7, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 1.75, + 'line-height': 2.25, + 'letter-spacing': '0', + }, + xlg: { + step: 8, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 2, + 'line-height': 2.5, + 'letter-spacing': '0', + }, + max: { + step: 8, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 2, + 'line-height': 2.5, + 'letter-spacing': '0', + }, + }, + + 'expressive-heading-05': { + sm: { + step: 8, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 2, + 'line-height': 2.5, + 'letter-spacing': '0', + }, + md: { + step: 9, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 2.25, + 'line-height': 2.75, + 'letter-spacing': '0', + }, + lg: { + step: 10, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 2.625, + 'line-height': 3.125, + 'letter-spacing': '0', + }, + xlg: { + step: 11, + font: 'IBM Plex Sans', + 'font-weight': '400', + 'font-size': 3, + 'line-height': 3.5, + 'letter-spacing': '0', + }, + max: { + step: 13, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 3.75, + 'line-height': 4.375, + 'letter-spacing': '0', + }, + }, + 'expressive-paragraph-01': { + sm: { + step: 6, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 1.5, + 'line-height': 1.875, + 'letter-spacing': '0', + }, + md: { + step: 6, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 1.5, + 'line-height': 1.875, + 'letter-spacing': '0', + }, + lg: { + step: 7, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 1.75, + 'line-height': 2.25, + 'letter-spacing': '0', + }, + xlg: { + step: 7, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 1.75, + 'line-height': 2.25, + 'letter-spacing': '0', + }, + max: { + step: 8, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 2, + 'line-height': 2.5, + 'letter-spacing': '0', + }, + }, + 'quotation-01': { + sm: { + step: 5, + font: 'IBM Plex Serif', + 'font-weight': '400', + 'font-size': 1.25, + 'line-height': 1.625, + 'letter-spacing': '0', + }, + md: { + step: 5, + font: 'IBM Plex Serif', + 'font-weight': '400', + 'font-size': 1.25, + 'line-height': 1.625, + 'letter-spacing': '0', + }, + lg: { + step: 6, + font: 'IBM Plex Serif', + 'font-weight': '400', + 'font-size': 1.5, + 'line-height': 1.875, + 'letter-spacing': '0', + }, + xlg: { + step: 7, + font: 'IBM Plex Serif', + 'font-weight': '300', + 'font-size': 1.75, + 'line-height': 2.25, + 'letter-spacing': '0', + }, + max: { + step: 8, + font: 'IBM Plex Serif', + 'font-weight': '300', + 'font-size': 2, + 'line-height': 2.5, + 'letter-spacing': '0', + }, + }, + 'quotation-02': { + sm: { + step: 8, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 2, + 'line-height': 2.5, + 'letter-spacing': '0', + }, + md: { + step: 9, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 2.25, + 'line-height': 2.75, + 'letter-spacing': '0', + }, + lg: { + step: 10, + font: 'IBM Plex Serif', + 'font-weight': '300', + 'font-size': 2.625, + 'line-height': 3.125, + 'letter-spacing': '0', + }, + xlg: { + step: 11, + font: 'IBM Plex Serif', + 'font-weight': '300', + 'font-size': 3, + 'line-height': 3.5, + 'letter-spacing': '0', + }, + max: { + step: 13, + font: 'IBM Plex Serif', + 'font-weight': '300', + 'font-size': 3.75, + 'line-height': 4.375, + 'letter-spacing': '0', + }, + }, + 'display-01': { + sm: { + step: 10, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 2.625, + 'line-height': 3.125, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + md: { + step: 10, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 2.625, + 'line-height': 3.125, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + lg: { + step: 12, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 3.375, + 'line-height': 4, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + xlg: { + step: 13, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 3.75, + 'line-height': 4.375, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + max: { + step: 15, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 4.75, + 'line-height': 5.375, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + }, + 'display-02': { + sm: { + step: 10, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 2.625, + 'line-height': 3.125, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + md: { + step: 10, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 2.625, + 'line-height': 3.125, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + lg: { + step: 12, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 3.375, + 'line-height': 4, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + xlg: { + step: 13, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 3.75, + 'line-height': 4.375, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + max: { + step: 15, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 4.75, + 'line-height': 5.375, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + }, + 'display-03': { + sm: { + step: 10, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 2.625, + 'line-height': 3.125, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + md: { + step: 14, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 4.25, + 'line-height': 4.875, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + lg: { + step: 17, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 5.75, + 'line-height': 6.375, + 'letter-spacing': '-0.64', + warning: 'Never use this style as the main headline', + }, + xlg: { + step: 20, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 7.625, + 'line-height': 8.125, + 'letter-spacing': '-0.64', + warning: 'Never use this style as the main headline', + }, + max: { + step: 23, + font: 'IBM Plex Sans', + 'font-weight': '300', + 'font-size': 9.75, + 'line-height': 10.25, + 'letter-spacing': '-0.96', + warning: 'Never use this style as the main headline', + }, + }, + 'display-04': { + sm: { + step: 10, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 2.625, + 'line-height': 3.125, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + md: { + step: 14, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 4.25, + 'line-height': 4.875, + 'letter-spacing': '0', + warning: 'Never use this style as the main headline', + }, + lg: { + step: 17, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 5.75, + 'line-height': 6.375, + 'letter-spacing': -0.64, + warning: 'Never use this style as the main headline', + }, + xlg: { + step: 20, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 7.625, + 'line-height': 8.125, + 'letter-spacing': -0.64, + warning: 'Never use this style as the main headline', + }, + max: { + step: 23, + font: 'IBM Plex Sans', + 'font-weight': '600', + 'font-size': 9.75, + 'line-height': 10.25, + 'letter-spacing': -0.96, + warning: 'Never use this style as the main headline', + }, + }, +}; + +const typeSets = { + supportingStyle: [ + { + description: + 'This is for inline code snippets and smaller code elements.', + version: 'mono', + key: 'code-01', + name: 'code-01', + }, + { + description: 'This is for large code snippets and larger code elements.', + version: 'mono', + key: 'code-02', + name: 'code-02', + }, + { + description: + 'This is for captions or legal content in a layout — not for body copy.', + key: 'caption-01', + name: 'caption-01', + }, + { + description: + 'This is for explanatory helper text that appears below a field title within a component.', + key: 'helper-text-01', + name: 'helper-text-01', + }, + ], + supportingStyles: [ + { + description: + 'This is for inline code snippets and smaller code elements.', + version: 'mono', + key: 'code-01', + name: 'code-01', + }, + { + description: 'This is for large code snippets and larger code elements.', + version: 'mono', + key: 'code-02', + name: 'code-02', + }, + { + description: 'This is for field labels in components and error messages.', + key: 'label-01', + name: 'label-01', + }, + { + description: + 'This is for explanatory helper text that appears below a field title within a component.', + key: 'helper-text-01', + name: 'helper-text-01', + }, + ], + body: [ + { + description: + 'This is for short paragraphs with no more than four lines and is commonly used in components.', + key: 'body-short-01', + name: 'body-short-01', + }, + { + description: + 'This is commonly used in both the expressive and the productive type theme layouts for long paragraphs with more than four lines. It is a good size for comfortable, long-form reading. Use this for longer body copy in components such as accordion or structured list. Always left-align this type; never center it.', + key: 'body-long-01', + name: 'body-long-01', + }, + { + description: + 'This is for short paragraphs with no more than four lines and is commonly used in the expressive type theme for layouts.', + key: 'body-short-02', + name: 'body-short-02', + }, + { + description: + 'This is commonly used in the expressive type theme layouts for long paragraphs with more than four lines. The looser line height and larger size makes for comfortable, long-form reading, in mediums that allow for more space. This size type is rarely used for body copy in components. Always left-align type; never center it.', + key: 'body-long-02', + name: 'body-long-02', + }, + ], + fixedHeadings: [ + { + description: 'This is for component and layout headings.', + key: 'heading-01', + name: 'heading-01', + }, + { + description: 'This is for component and layout headings.', + key: 'heading-02', + name: 'heading-02', + }, + { + description: 'This is for component and layout headings.', + key: 'productive-heading-03', + name: 'productive-heading-03', + }, + { + description: 'This is for layout headings.', + key: 'productive-heading-04', + name: 'productive-heading-04', + }, + { + description: 'This is for layout headings.', + key: 'productive-heading-05', + name: 'productive-heading-05', + }, + ], + fixedHeading: [ + { + description: 'This is for component and layout headings.', + key: 'heading-01', + name: 'heading-01', + }, + { + description: 'This is for component and layout headings.', + key: 'heading-02', + name: 'heading-02', + }, + ], + fluidHeadings: [ + { + description: 'Heading style', + key: 'expressive-heading-04', + name: 'expressive-heading-04', + }, + { + description: 'Heading style', + key: 'expressive-heading-05', + name: 'expressive-heading-05', + }, + ], + FluidParagraphsAndQuotes: [ + { + description: 'Paragraph', + key: 'expressive-paragraph-01', + name: 'expressive-paragraph-01', + }, + { + description: '“Quote.”', + key: 'quotation-01', + name: 'quotation-01', + }, + { + description: '“Quote.”', + key: 'quotation-02', + name: 'quotation-02', + }, + ], + fluidDisplay: [ + { + description: 'Display', + key: 'display-01', + name: 'display-01', + }, + { + description: 'Display', + key: 'display-02', + name: 'display-02', + }, + { + description: 'Display', + key: 'display-03', + name: 'display-03', + }, + { + description: 'Display', + key: 'display-04', + name: 'display-04', + }, + ], +}; + +const breakpoints = { + sm: Number(carbonBreakpoints.sm.width.replace('rem', '')) * baseFontSize, + md: Number(carbonBreakpoints.md.width.replace('rem', '')) * baseFontSize, + lg: Number(carbonBreakpoints.lg.width.replace('rem', '')) * baseFontSize, + xlg: Number(carbonBreakpoints.xlg.width.replace('rem', '')) * baseFontSize, + max: Number(carbonBreakpoints.max.width.replace('rem', '')) * baseFontSize, +}; + +const indexOfCurrentBreakpoint = viewportWidth => + findLastIndex(values(breakpoints), width => viewportWidth >= width); + +const nextLargerBreakpointPx = viewportWidth => + values(breakpoints)[indexOfCurrentBreakpoint(viewportWidth) + 1]; + +const isWithinBreakpoint = (viewportWidth, currentBreakpoint) => { + if (viewportWidth === currentBreakpoint) return true; + return ( + viewportWidth >= currentBreakpoint && + viewportWidth < nextLargerBreakpointPx(currentBreakpoint) + ); +}; + +class TypesetStyle extends React.Component { + state = { + simulatedScreenWidth: 1056, + tab: 0, + sticky: false, + mobile: false, + }; + + componentDidMount() { + if (window.innerWidth < 500) { + // eslint-disable-next-line react/no-did-mount-set-state + this.setState({ + mobile: true, + }); + } + this.addResizeListener(); + this.addScrollListener(); + } + + getButtons = () => + Object.keys(breakpoints).map(breakpointName => ( + + )); + + toggleBreakpoint = e => { + this.setState({ simulatedScreenWidth: Number(e.target.value) }); + }; + + toggleSet = value => { + this.setState({ tab: value }); + }; + + addResizeListener() { + window.addEventListener('resize', () => { + if (window.innerWidth < 500) { + this.setState({ + mobile: true, + }); + } else if (window.innerWidth > 500) { + this.setState({ + mobile: false, + }); + } + }); + } + + addScrollListener() { + document.addEventListener('scroll', () => { + if (this.refs.stickyBar) { + if (this.refs.stickyBar.getBoundingClientRect().top <= 104) { + this.setState({ + sticky: true, + }); + } else if (this.refs.stickyBar.getBoundingClientRect().top > 104) { + this.setState({ + sticky: false, + }); + } + } + }); + } + + render() { + const { + navBar, + banner, + secondary, + top, + breakpointControls, + typesets, + } = this.props; + + const typesetStyleStickyClassnames = classnames( + [`${prefix}--typeset-style-controls-sticky`], + [`${prefix}--row`], + { + [`${prefix}--typeset-style-controls-sticky-stuck`]: this.state.sticky, + } + ); + + return ( +
+ + {breakpointControls && ( + <> +
+
+
+ + Breakpoints + +
+ {this.getButtons()} +
+
+
+ + Screen width + + + +
+
+ + )} + +
+ {typesets + .replace(', ', ',') + .split(',') + .map(typeset => ( + <> +

+ {typeset.replace(/([a-z])([A-Z])/g, '$1 $2').toLowerCase()} +

+ + + ))} +
+
+ ); + } +} + +export default TypesetStyle; + +// these props are passed onto the sticky container +TypesetStyle.propTypes = { + // if site has banner at top ( ex. go to v1) + banner: PropTypes.bool, + + // if page navBar is showing / hiding, toggle this on/off + navBar: PropTypes.bool, + + // for items that are on pages that already have a sticky item + secondary: PropTypes.bool, + + // if custom top is necessary, must include units - (rem, px, etc) + top: PropTypes.string, + + // show / hide breakpoint controls + breakpointControls: PropTypes.bool, + + // comma separated list of typesets to display + typesets: PropTypes.string, +}; diff --git a/src/components/TypesetStyle/index.js b/src/components/TypesetStyle/index.js new file mode 100644 index 00000000000..474270c8c82 --- /dev/null +++ b/src/components/TypesetStyle/index.js @@ -0,0 +1,3 @@ +import TypesetStyle from './TypesetStyle'; + +export default TypesetStyle; diff --git a/src/components/TypesetStyle/typeset-style.scss b/src/components/TypesetStyle/typeset-style.scss new file mode 100644 index 00000000000..eacd7a0f3a1 --- /dev/null +++ b/src/components/TypesetStyle/typeset-style.scss @@ -0,0 +1,459 @@ +$prefix: 'bx'; + +// Typeset Style +.#{$prefix}--typeset-style-container { + position: relative; + padding: 0 $spacing-03; + margin-bottom: $spacing-09; + + @include carbon--breakpoint('md') { + padding: 0; + left: 0; + margin-right: 0; + } + + @include carbon--breakpoint('lg') { + margin-top: 0; + left: 0.5rem; + margin-right: $spacing-03; + } +} + +.#{$prefix}--typeset-style-container .page-h4 { + margin-top: $spacing-09; + display: inline-block; + + &:before { + display: none; + } + + &::first-letter { + text-transform: uppercase; + } +} + +.#{$prefix}--typeset-style-button { + background-color: transparent; + border: none; + border-radius: 0; + height: 100%; + margin: 0; + padding: 0 $spacing-05; + text-transform: capitalize; + z-index: 4; + + &:hover { + background-color: $carbon--gray-20; + } + + &.selected { + background-color: $carbon--gray-100; + color: $carbon--gray-10; + + &:hover { + background-color: $carbon--gray-100; + } + } + + &:focus { + outline: 2px solid $focus; + outline-offset: 0; + position: relative; + } +} + +.#{$prefix}--typeset-style-controls { + height: 100%; + left: 0; + position: absolute !important; + top: 0; + width: 100vw; + + @include carbon--breakpoint('md') { + margin-left: 0; + width: 100%; + } +} + +.#{$prefix}--typeset-style-controls-sticky { + align-items: center; + background-color: $carbon--white-0; + width: auto; + z-index: 2; + box-sizing: content-box; +} + +.#{$prefix}--typeset-style-controls-sticky-stuck { + box-shadow: 0px 2px 6px 0px rgba($carbon--black-100, 0.2); + + &:before, + &:after { + content: ''; + position: absolute; + background: $carbon--gray-10; + height: 6rem; + width: 1rem; + + @include carbon--breakpoint('md') { + height: 4rem; + } + } + + &:before { + left: -2rem; + } + + &:after { + right: -2rem; + } +} + +.#{$prefix}--typeset-style-nav-shiv { + width: 100%; + height: 1rem; +} + +.#{$prefix}--typeset-style-breakpoint-controls { + height: 3rem; + align-items: center; + display: flex; + overflow-x: auto; + white-space: nowrap; + padding-left: $spacing-05; + padding-right: 0; + width: 100%; + + @include carbon--breakpoint('md') { + width: 62.5%; + } + + @include carbon--breakpoint('lg') { + width: 50%; + } +} + +.#{$prefix}--typeset-style-screen-width-label { + padding-right: $spacing-05; + display: inline-block; +} + +.#{$prefix}--typeset-style-screen-controls { + align-items: center; + height: 3rem; + border-top: 1px solid $carbon--gray-20; + padding-left: $spacing-05; + padding-right: $spacing-05; + display: grid; + grid-template-columns: auto 1fr auto; + width: 100%; + + @include carbon--breakpoint('md') { + border-top: none; + border-left: 1px solid $carbon--gray-20; + width: 37.5%; + } + + @include carbon--breakpoint('lg') { + width: 50%; + } +} + +.#{$prefix}--typeset-style-screen-label { + height: auto; + margin-bottom: 0; + // Need to set the width explicitly to make sure the slider + // keeps the same size when going from three to four digits (999-1000) + min-width: 3.4rem; + text-align: right; +} + +.#{$prefix}--typeset-style-input { + margin: 0; + margin-right: rem(20px); + width: 100%; +} + +.#{$prefix}--typeset-style-toggle-container { + position: relative; + z-index: 1; +} + +.#{$prefix}--typeset-style-toggle-button { + background-color: $carbon--white-0; + box-shadow: inset 0 -1px 0 0 $carbon--gray-20; + color: $carbon--gray-100; + border: none; + cursor: pointer; + margin: 0; + height: 3rem; + + input { + margin: 0; + visibility: hidden; + width: 0; + } + + &.checked { + background-color: $carbon--gray-100; + color: $carbon--white-0; + + &:hover { + background-color: $carbon--gray-100; + } + } + + &:hover { + background-color: $carbon--gray-20; + } +} + +.#{$prefix}--typeset-style-button-controls-container { + height: 100%; + margin-left: auto; +} + +.#{$prefix}--typeset-style-breakpoints-container { + position: relative; + margin-top: $spacing-05; + + @include carbon--breakpoint('md') { + margin-top: 0; + } +} + +.#{$prefix}--typeset-style-section-spacer { + margin-bottom: calc(1rem + 1px); +} + +.#{$prefix}--typeset-style-title-shiv { + padding-top: $spacing-05; + background-color: $carbon--gray-10; + position: relative; +} + +.#{$prefix}--typeset-style-group-title-container { + background-color: $carbon--white-0; + height: 3rem; + padding: $spacing-05; + border-bottom: 1px solid $carbon--gray-20; + display: flex; + flex-direction: row; + align-content: center; +} + +.#{$prefix}--typeset-style-group-title { + margin: 0; + padding: 0; +} + +// ------------------------------------------------------ +// Input Range +// ------------------------------------------------------ +.#{$prefix}--input-range { + appearance: none; + font-size: 0px; + position: relative; + cursor: pointer; + // Provide a larger interaction hit area + padding-top: $spacing-03; + padding-bottom: $spacing-03; + width: 100%; + + // Remove extra padding on Edge that causes vertical misalignment + // IE Edge 16+ CSS + // See https://browserstrangeness.github.io/css_hacks.html + @supports (-ms-ime-align: auto) { + padding-top: 0; + padding-bottom: 0; + } + + // Chaining the selectors doesn't work because browsers. + // See https://css-tricks.com/sliding-nightmare-understanding-range-input/#structure + &::-webkit-slider-runnable-track { + background: $carbon--gray-20; + height: rem(1px); + } + &::-moz-range-track { + background: $carbon--gray-20; + height: rem(1px); + } + + &::-webkit-slider-thumb { + appearance: none; + background: $carbon--black-100; + border: 0; + border-radius: 100%; + height: rem(14px); + margin-top: rem(-7px); + width: rem(14px); + transition-property: height, width, margin; + transition-duration: 0.1s; + transition-timing-function: $carbon--standard-easing; + } + &::-moz-range-thumb { + appearance: none; + background: $carbon--black-100; + border: 0; + border-radius: 100%; + height: rem(14px); + margin-top: rem(-7px); + width: rem(14px); + transition-property: height, width, margin; + transition-duration: 0.1s; + transition-timing-function: $carbon--standard-easing; + } + + &::-ms-track { + background: transparent; + border-color: transparent; + border-width: rem(14px) 0; + color: transparent; + height: rem(1px); + } + &::-ms-fill-lower { + background: $carbon--black-100; + } + &::-ms-fill-upper { + background: $carbon--black-100; + } + &::-ms-thumb { + appearance: none; + background: $carbon--black-100; + border-radius: 100%; + border: 0; + height: rem(14px); + margin-top: rem(-1px); + width: rem(14px); + } + + &:after { + background: $carbon--black-100; + content: ''; + position: absolute; + height: rem(1px); + width: var(--track-width); + } + + &:hover, + &:active { + &::-webkit-slider-thumb { + margin-top: rem(-9px); + width: rem(18px); + height: rem(18px); + } + &::-moz-range-thumb { + margin-top: rem(-9px); + width: rem(18px); + height: rem(18px); + } + &::-ms-thumb { + margin-top: rem(-2px); + width: rem(18px); + height: rem(18px); + } + } + + &:focus { + outline: 2px solid $focus; + outline-offset: 0; + } +} + +// ------------------------------------------------------ +// Sticky Container +// ------------------------------------------------------ + +.#{$prefix}--sticky-container { + position: sticky; + z-index: 5; + top: 0; + transition-property: top; + transition-duration: $transition--expansion; + transition-timing-function: $carbon--standard-easing; +} + +.#{$prefix}--sticky-container-visible { + top: 3rem; + + &.#{$prefix}--sticky-container-banner { + top: 5.5rem; + } +} + +.#{$prefix}--sticky-container-hidden { + &.#{$prefix}--sticky-container-banner { + top: 2.5rem; + } +} + +.#{$prefix}--sticky-container-secondary { + z-index: 4; +} + +.#{$prefix}--sticky-container-secondary-hidden { + top: 3rem; + + &.#{$prefix}--sticky-container-banner { + top: 5.5rem; + } +} + +.#{$prefix}--sticky-container-secondary-visible { + top: 6rem; + + &.#{$prefix}--sticky-container-banner { + top: 8.5rem; + } +} + +// ------------------------------------------------------ +// Typeset Example +// ------------------------------------------------------ +.#{$prefix}--typeset-example-container { + margin-top: $spacing-05; +} + +.#{$prefix}--typeset-example { + margin-top: $spacing-05; +} + +.#{$prefix}--typeset-example-row { + background-color: $carbon--white-0; + min-height: rem(216px); +} + +.#{$prefix}--typeset-example-group-title { + background-color: $carbon--gray-20; + height: 4rem; +} + +.#{$prefix}--typeset-example-description { + padding: $spacing-05 15% $spacing-05 $spacing-05; + overflow: hidden; + + @include carbon--breakpoint('md') { + width: 62.5%; + } + + @include carbon--breakpoint('lg') { + width: 66.7%; + } +} + +.#{$prefix}--typeset-example-specs { + padding: $spacing-05; + width: 33.3%; + + @include carbon--breakpoint('md') { + border-left: 1px solid $carbon--gray-20; + } +} + +.#{$prefix}--typeset-example-specs-text { + margin-bottom: $spacing-03; +} + +.#{$prefix}--typeset-example-code-style { + display: block; + margin-top: $spacing-03; +} diff --git a/src/pages/guidelines/typography/expressive.mdx b/src/pages/guidelines/typography/expressive.mdx index eb43a81f55c..cc518925766 100644 --- a/src/pages/guidelines/typography/expressive.mdx +++ b/src/pages/guidelines/typography/expressive.mdx @@ -4,7 +4,7 @@ title: Typography tabs: ['Overview', 'Productive', 'Expressive'] --- -import TypesetStyle from '@carbon/addons-website/src/components/TypesetStyle'; +import TypesetStyle from 'components/TypesetStyle'; ## Expressive type sets diff --git a/src/pages/guidelines/typography/productive.mdx b/src/pages/guidelines/typography/productive.mdx index aff39b6ab71..178bb471bc2 100644 --- a/src/pages/guidelines/typography/productive.mdx +++ b/src/pages/guidelines/typography/productive.mdx @@ -4,7 +4,7 @@ title: Typography tabs: ['Overview', 'Productive', 'Expressive'] --- -import TypesetStyle from '@carbon/addons-website/src/components/TypesetStyle'; +import TypesetStyle from 'components/TypesetStyle'; ## IBM Productive type set diff --git a/yarn.lock b/yarn.lock index e6b919ecf26..3ec35571de4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8807,7 +8807,7 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.0.0, lodash@^4.11.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@~4.17.10: +lodash@^4.0.0, lodash@^4.11.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@~4.17.10: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==