|  | 
|  | 1 | +import { Meta, StoryObj } from '@storybook/react'; | 
|  | 2 | +import { Property } from 'csstype'; | 
|  | 3 | +import { useEffect, useState } from 'react'; | 
|  | 4 | +import typographyVarsAsString from '../../00-config/vars/typography.css?raw'; | 
|  | 5 | +import getCssVariables from '../../06-utility/storybook/getCssVariables'; | 
|  | 6 | +import styles from './typographic-scale.module.css'; | 
|  | 7 | + | 
|  | 8 | +const typographyVars = typographyVarsAsString | 
|  | 9 | +  .replace(':root {', '') | 
|  | 10 | +  .replace('}', '') | 
|  | 11 | +  .split(';') | 
|  | 12 | +  .map((e: string) => { | 
|  | 13 | +    return e.trim(); | 
|  | 14 | +  }) | 
|  | 15 | +  .filter((e: string) => e.includes('--responsive-font-size')) | 
|  | 16 | +  .map((e: string) => { | 
|  | 17 | +    return e.replace(')', '').split('(').pop(); | 
|  | 18 | +  }); | 
|  | 19 | + | 
|  | 20 | +const typographyVarsMax = typographyVars.map((e: string) => { | 
|  | 21 | +  return e.split(' ').pop(); | 
|  | 22 | +}); | 
|  | 23 | +const typographyVarsMin = typographyVars.map((e: string) => { | 
|  | 24 | +  return e.split(' ', 1).pop(); | 
|  | 25 | +}); | 
|  | 26 | + | 
|  | 27 | +const settings: Meta = { | 
|  | 28 | +  title: 'Global/Typography/Typographic Scale', | 
|  | 29 | +}; | 
|  | 30 | + | 
|  | 31 | +interface FontOptions { | 
|  | 32 | +  [name: string]: Property.FontFamily; | 
|  | 33 | +} | 
|  | 34 | + | 
|  | 35 | +interface ResponsiveFontSizeOptions { | 
|  | 36 | +  [number: number]: string; | 
|  | 37 | +} | 
|  | 38 | + | 
|  | 39 | +const TypographicScale: StoryObj = { | 
|  | 40 | +  render: function Render() { | 
|  | 41 | +    const [fonts, setFonts] = useState<FontOptions | undefined>(undefined); | 
|  | 42 | +    const [responsiveFontSizes, setResponsiveFontSizes] = useState< | 
|  | 43 | +      ResponsiveFontSizeOptions | undefined | 
|  | 44 | +    >(undefined); | 
|  | 45 | + | 
|  | 46 | +    useEffect(() => { | 
|  | 47 | +      const allVars = getCssVariables(); | 
|  | 48 | + | 
|  | 49 | +      const fonts = allVars.reduce((allFonts, [key, value]) => { | 
|  | 50 | +        if (key.indexOf('--font-family') === 0) { | 
|  | 51 | +          const name = | 
|  | 52 | +            key.substring(14).charAt(0).toUpperCase() + | 
|  | 53 | +            key.substring(14).slice(1); | 
|  | 54 | +          allFonts[name] = value; | 
|  | 55 | +        } | 
|  | 56 | +        return allFonts; | 
|  | 57 | +      }, {} as FontOptions); | 
|  | 58 | +      setFonts(fonts); | 
|  | 59 | + | 
|  | 60 | +      const fontSizes = allVars.reduce( | 
|  | 61 | +        (allResponsiveFontSizes, [key, value]) => { | 
|  | 62 | +          if (key.indexOf('--responsive-font-size') === 0) { | 
|  | 63 | +            const number = parseInt(key.substring(23)); | 
|  | 64 | +            allResponsiveFontSizes[number] = value; | 
|  | 65 | +          } | 
|  | 66 | +          return allResponsiveFontSizes; | 
|  | 67 | +        }, | 
|  | 68 | +        {} as ResponsiveFontSizeOptions, | 
|  | 69 | +      ); | 
|  | 70 | +      setResponsiveFontSizes(fontSizes); | 
|  | 71 | +    }, []); | 
|  | 72 | +    return ( | 
|  | 73 | +      <> | 
|  | 74 | +        {fonts && | 
|  | 75 | +          Object.entries(fonts) | 
|  | 76 | +            .sort((fontA, fontB) => { | 
|  | 77 | +              // Sort fonts so that Primary and Secondary (if used) appear at the | 
|  | 78 | +              // top of the list. | 
|  | 79 | +              if (fontA[0].toLowerCase().includes('primary')) { | 
|  | 80 | +                return -1; | 
|  | 81 | +              } | 
|  | 82 | +              if (fontB[0].toLowerCase().includes('primary')) { | 
|  | 83 | +                return 1; | 
|  | 84 | +              } | 
|  | 85 | +              if (fontA[0].toLowerCase().includes('secondary')) { | 
|  | 86 | +                return -1; | 
|  | 87 | +              } | 
|  | 88 | +              if (fontB[0].toLowerCase().includes('secondary')) { | 
|  | 89 | +                return 1; | 
|  | 90 | +              } | 
|  | 91 | +              return 0; | 
|  | 92 | +            }) | 
|  | 93 | +            .map(([name, fontFamily]) => ( | 
|  | 94 | +              <div className={styles['typographic-scale']} key={name}> | 
|  | 95 | +                <h2 className={styles.heading}>{name}</h2> | 
|  | 96 | +                <div style={{ fontFamily }}> | 
|  | 97 | +                  {responsiveFontSizes && | 
|  | 98 | +                    Object.entries(responsiveFontSizes).map( | 
|  | 99 | +                      ([number, responsiveFontSize]) => ( | 
|  | 100 | +                        <> | 
|  | 101 | +                          <div className={styles.row} key={`${name}-${number}`}> | 
|  | 102 | +                            <div className={styles.label}>{number}</div> | 
|  | 103 | +                            <div | 
|  | 104 | +                              className={styles.preview} | 
|  | 105 | +                              style={{ | 
|  | 106 | +                                fontSize: responsiveFontSize, | 
|  | 107 | +                              }} | 
|  | 108 | +                            > | 
|  | 109 | +                              This text goes from{' '} | 
|  | 110 | +                              {typographyVarsMin[parseInt(number) - 1]} to{' '} | 
|  | 111 | +                              {typographyVarsMax[parseInt(number) - 1]}. | 
|  | 112 | +                            </div> | 
|  | 113 | +                          </div> | 
|  | 114 | +                        </> | 
|  | 115 | +                      ), | 
|  | 116 | +                    )} | 
|  | 117 | +                </div> | 
|  | 118 | +              </div> | 
|  | 119 | +            ))} | 
|  | 120 | +      </> | 
|  | 121 | +    ); | 
|  | 122 | +  }, | 
|  | 123 | +  args: {}, | 
|  | 124 | +}; | 
|  | 125 | + | 
|  | 126 | +export default settings; | 
|  | 127 | +export { TypographicScale }; | 
0 commit comments