diff --git a/v7/classes/custom/border.mjs b/v7/classes/custom/border.mjs deleted file mode 100644 index 3fde2ee..0000000 --- a/v7/classes/custom/border.mjs +++ /dev/null @@ -1,26 +0,0 @@ -const defaultWidths = [1, 2, 4] - -export default function border({ breakpoint = '', widths = defaultWidths } = {}) { - let output = /*css*/` -/*** Border ***/ -.border-solid${breakpoint}{border-style:solid;} -.border-dashed${breakpoint}{border-style:dashed;} -.border-dotted${breakpoint}{border-style:dotted;} -.border-double${breakpoint}{border-style:double;} -.border-none${breakpoint}{border-style:none;} -.border-bs-none${breakpoint}{border-block-start:none;} -.border-be-none${breakpoint}{border-block-end:none;} -.border-is-none${breakpoint}{border-inline-start:none;} -.border-ie-none${breakpoint}{border-inline-end:none;} -` - widths.map((w, i) => { - output += ` -.border${i}${breakpoint}{border-width:${w}px;} -.border-bs${i}${breakpoint}{border-block-start-width:${w}px;} -.border-be${i}${breakpoint}{border-block-end-width:${w}px;} -.border-is${i}${breakpoint}{border-inline-start-width:${w}px;} -.border-ie${i}${breakpoint}{border-inline-end-width:${w}px;} -` - }) - return output -} diff --git a/v7/classes/custom/borders.mjs b/v7/classes/custom/borders.mjs new file mode 100644 index 0000000..0939bef --- /dev/null +++ b/v7/classes/custom/borders.mjs @@ -0,0 +1,66 @@ +import borderRadius from '../../properties/border-radius.mjs' +import borderWidths from '../../properties/border-widths.mjs' +import directions from '../../lib/directions.mjs' +import getCustomProperties from '../../lib/getCustomProperties.mjs' + +export default function borders(state = {}) { + const { config = {}, breakpoint = '' } = state + const radiusProperties = getCustomProperties(borderRadius({ config })) + const widthProperties = getCustomProperties(borderWidths({ config })) + const directionEntries = Object.entries(directions) + + let output = '/*** Borders ***/' + + // Border styles + const borderStyles = ['solid', 'dashed', 'dotted', 'double', 'none'] + borderStyles.forEach(style => { + output += '\n' + output += `.border-${style} { border-style: ${style}; }` + }) + directionEntries.forEach(dir => { + borderStyles.forEach(style => { + output += '\n' + output += `.border-${dir[0]}-${style} { border-${dir[1]}-style: ${style}; }` + }) + }) + + // Border widths scale + if (widthProperties.length) { + widthProperties.forEach((w, i) => { + output += '\n' + output += `.border${i} { border-width: var(${w}); }` + + directionEntries.forEach(dir => { + output += '\n' + output += `.border-${dir[0]}${i} { border-${dir[1]}-width: var(${w}); }` + }) + }) + } + + // Radius builtins + output += ` +.radius-100${breakpoint} { border-radius: 100%; } +.radius-pill${breakpoint} { border-radius: 9999px; } +.radius-none${breakpoint} { border-radius: 0; }` + + // Directional null radii + directionEntries.forEach(dir => { + output += '\n' + output += `.radius-${dir[0]}-none${breakpoint} { border-${dir[1]}-radius: 0; }` + }) + + // Radii scale + if (radiusProperties.length) { + radiusProperties.forEach((r, i) => { + output += '\n' + output += `.radius${i} { border-radius: var(${r}); }` + + directionEntries.forEach(dir => { + output += '\n' + output += `.radius-${dir[0]}${i} { border-${dir[1]}-radius: var(${r}); }` + }) + }) + } + + return output +} diff --git a/v7/classes/custom/font-family.mjs b/v7/classes/custom/font-family.mjs index 16c4f17..94fa945 100644 --- a/v7/classes/custom/font-family.mjs +++ b/v7/classes/custom/font-family.mjs @@ -1,18 +1,19 @@ -const defaultFonts = ` -.font-sans{font-family: system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif;} -.font-serif{font-family: Georgia, Cambria, Times New Roman, Times, serif;} -.font-mono{font-family: Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;} -` +import getCustomProperties from '../../lib/getCustomProperties.mjs' +import fonts from '../../properties/fonts.mjs' -export default function family({ fonts = defaultFonts } = {}) { - const output = Object.keys(fonts).length - ? Object.keys(fonts) - .map(key => `.font-${key}{font-family: ${fonts[key]};}`) - .join('\n') - : defaultFonts +export default function fontFamily(state = {}) { + const { config = {} } = state + const families = getCustomProperties(fonts({ config })) - return /*css*/` -/*** Font Family ***/ -${output} -` + let output = '' + + if (families.length) { + output += '/*** Font Family ***/' + families.forEach(family => { + output += '\n' + output += `.${family.replace('--', '')} { font-family: var(${family}); }` + }) + } + + return output } diff --git a/v7/classes/custom/font-size.mjs b/v7/classes/custom/font-size.mjs index 46fe1ee..aca2eeb 100644 --- a/v7/classes/custom/font-size.mjs +++ b/v7/classes/custom/font-size.mjs @@ -1,17 +1,19 @@ -import { generateTypeScaleProperties, getScalePropertyNames, defaultConfig } from '../../lib/scales.mjs' +import getCustomProperties from '../../lib/getCustomProperties.mjs' +import { generateTypeScaleProperties } from '../../lib/scales.mjs' -export default function fontSize({ breakpoint = '', typeScale = defaultConfig } = {}) { - let output = ` -/*** Font Sizes ***/ -` +export default function fontSize(state = {}) { + const { config = {}, breakpoint = '' } = state + const sizes = getCustomProperties(generateTypeScaleProperties(config.typeScale)) - const properties = generateTypeScaleProperties(typeScale) - const propertyNames = getScalePropertyNames(properties) + let output = '' - propertyNames.forEach(pn => { - const step = pn.replace('--text-', '') - output += `.text${step}${breakpoint}{font-size:var(${pn});}\n` - }) + if (sizes.length) { + output += '/*** Font Size ***/' + sizes.forEach(size => { + output += '\n' + output += `${size.replace('--text-', '.text')}${breakpoint} { font-size: var(${size}); }` + }) + } return output } diff --git a/v7/classes/custom/gap.mjs b/v7/classes/custom/gap.mjs index 5598428..5a87541 100644 --- a/v7/classes/custom/gap.mjs +++ b/v7/classes/custom/gap.mjs @@ -1,17 +1,19 @@ -import { generateSpaceScaleProperties, getScalePropertyNames, defaultConfig } from '../../lib/scales.mjs' +import getCustomProperties from '../../lib/getCustomProperties.mjs' +import { generateSpaceScaleProperties } from '../../lib/scales.mjs' -export default function gap({ breakpoint = '', spaceScale = defaultConfig } = {}) { - let output = ` -/*** Gap ***/ -` - const properties = generateSpaceScaleProperties(spaceScale) - const propertyNames = getScalePropertyNames(properties) +export default function gap(state = {}) { + const { config = {}, breakpoint = '' } = state + const sizes = getCustomProperties(generateSpaceScaleProperties(config.spaceScale)) - propertyNames.forEach(pn => { - const step = pn.replace('--space-', '') - output += `.gap${step}${breakpoint}{gap:var(${pn});}\n` - }) + let output = '' + if (sizes.length) { + output += '/*** Gap ***/' + sizes.forEach(size => { + output += '\n' + output += `.gap${size.replace('--space-', '')}${breakpoint} { gap: var(${size}); }` + }) + } return output } diff --git a/v7/classes/custom/grid.mjs b/v7/classes/custom/grid.mjs index 12962a0..3ab8770 100644 --- a/v7/classes/custom/grid.mjs +++ b/v7/classes/custom/grid.mjs @@ -1,28 +1,27 @@ -export default function grid({ - breakpoint = '', - steps = 6, -}) { - let output = /*css*/` -/*** Grid ***/ -.flow-row${breakpoint}{grid-auto-flow:row;} -.flow-col${breakpoint}{grid-auto-flow:column;} -.flow-row-dense${breakpoint}{grid-auto-flow:row dense;} -.flow-column-dense${breakpoint}{grid-auto-flow:column dense;} -.row-auto${breakpoint}{grid-row:auto;} -.col-auto${breakpoint}{grid-column:auto;} -.col-end-auto${breakpoint}{grid-column-end: auto;} -.rows-end-auto${breakpoint}{grid-row-end:auto;} -.rows-none${breakpoint}{grid-template-rows:none;} -` +export default function grid(state = {}) { + const { config = {}, breakpoint = '' } = state + const { grid = {} } = config + const { steps = 6 } = grid + + let output = `/*** Grid ***/ +.flow-row${breakpoint} { grid-auto-flow: row; } +.flow-col${breakpoint} { grid-auto-flow: column; } +.flow-row-dense${breakpoint} { grid-auto-flow: row dense; } +.flow-column-dense${breakpoint} { grid-auto-flow: column dense; } +.row-auto${breakpoint} { grid-row: auto; } +.col-auto${breakpoint} { grid-column: auto; } +.col-end-auto${breakpoint} { grid-column-end: auto; } +.rows-end-auto${breakpoint} { grid-row-end: auto; } +.rows-none${breakpoint} { grid-template-rows: none; }` for (let i = 1; i < steps + 1; i++) { - output += `.col-${i}${breakpoint}{grid-template-columns:repeat(${i}, minmax(0, 1fr));}\n` - output += `.col-span-${i}${breakpoint}{grid-column: span ${i} / span ${i};}\n` - output += `.col-start-${i}${breakpoint}{grid-column-start: ${i};}\n` - output += `.row-start-${i}${breakpoint}{grid-row-start: ${i};}\n` - output += `.col-end-${i}${breakpoint}{grid-column-end: ${i};}\n` - output += `.row-end-${i}${breakpoint}{grid-row-end: ${i};}\n` - output += `.row-${i}${breakpoint}{grid-template-rows: repeat(${i}, minmax(0, 1fr));}\n` + output += `.col-${i}${breakpoint} { grid-template-columns:repeat(${i}, minmax(0, 1fr)); }\n` + output += `.col-span-${i}${breakpoint} { grid-column: span ${i} / span ${i}; }\n` + output += `.col-start-${i}${breakpoint} { grid-column-start: ${i}; }\n` + output += `.row-start-${i}${breakpoint} { grid-row-start: ${i}; }\n` + output += `.col-end-${i}${breakpoint} { grid-column-end: ${i}; }\n` + output += `.row-end-${i}${breakpoint} { grid-row-end: ${i}; }\n` + output += `.row-${i}${breakpoint} { grid-template-rows: repeat(${i}, minmax(0, 1fr)); }` } return output diff --git a/v7/classes/custom/margin.mjs b/v7/classes/custom/margin.mjs index 0a53440..605d132 100644 --- a/v7/classes/custom/margin.mjs +++ b/v7/classes/custom/margin.mjs @@ -1,31 +1,31 @@ -import generateDirectionalVariants from '../../lib/generateDirectionalVariants.mjs' -import { defaultConfig } from '../../lib/scales.mjs' +import directions from '../../lib/directions.mjs' +import getCustomProperties from '../../lib/getCustomProperties.mjs' +import { generateSpaceScaleProperties } from '../../lib/scales.mjs' -export default function margin({ breakpoint = '', spaceScale = defaultConfig }) { - let output = /*css*/` -/*** Margin ***/ -.m-none${breakpoint}{margin:0} -.mb-none${breakpoint}{margin-block:0} -.mbs-none${breakpoint}{margin-block-start:0} -.mbe-none${breakpoint}{margin-block-end:0} -.mi-none${breakpoint}{margin-inline:0} -.mis-none${breakpoint}{margin-inline-start:0} -.mie-none${breakpoint}{margin-inline-end:0} -.m-auto${breakpoint}{margin:auto} -.mb-auto${breakpoint}{margin-block:auto} -.mbs-auto${breakpoint}{margin-block-start:auto} -.mbe-auto${breakpoint}{margin-block-end:auto} -.mi-auto${breakpoint}{margin-inline:auto} -.mis-auto${breakpoint}{margin-inline-start:auto} -.mie-auto${breakpoint}{margin-inline-end:auto} -` +export default function margin(state = {}) { + const { config = {}, breakpoint = '' } = state + const directionEntries = Object.entries(directions) + const sizes = getCustomProperties(generateSpaceScaleProperties(config.spaceScale)) - function template({ label, step, direction, value }) { - // Redefine `direction` arg with a formatted version of it, if the arg is truthy - if (direction) direction = `-${direction}` - return `.m${label}${step}${breakpoint}{margin${direction}:${value};}\n` + // Null margins + let output = '/*** Margin ***/\n' + output += `.m-none${breakpoint} { margin: 0; }` + directionEntries.forEach(dir => { + output += '\n' + output += `.m${dir[0]}${breakpoint}-none { margin-${dir[1]}: 0; }` + }) + + // Margin scale + if (sizes.length) { + sizes.forEach(size => { + output += '\n' + output += `.m${size.replace('--space-', '')}${breakpoint} { margin: var(${size}); }}` + directionEntries.forEach(dir => { + output += '\n' + output += `.m${dir[0]}${size.replace('--space-', '')}${breakpoint} { margin-${dir[1]}: var(${size}); }` + }) + }) } - output += generateDirectionalVariants({ spaceScale, template }) return output } diff --git a/v7/classes/custom/padding.mjs b/v7/classes/custom/padding.mjs index 38d27e8..f3daa08 100644 --- a/v7/classes/custom/padding.mjs +++ b/v7/classes/custom/padding.mjs @@ -1,23 +1,32 @@ -import generateDirectionalVariants from '../../lib/generateDirectionalVariants.mjs' -import { defaultConfig } from '../../lib/scales.mjs' +import directions from '../../lib/directions.mjs' +import getCustomProperties from '../../lib/getCustomProperties.mjs' +import { generateSpaceScaleProperties } from '../../lib/scales.mjs' -export default function padding({ breakpoint = '', spaceScale = defaultConfig } = {}) { - let output = /*css*/` -/*** Padding ***/ -.p-none${breakpoint}{padding:0} -.pb-none${breakpoint}{padding-block:0} -.pbs-none${breakpoint}{padding-block-start:0} -.pbe-none${breakpoint}{padding-block-end:0} -.pi-none${breakpoint}{padding-inline:0} -.pis-none${breakpoint}{padding-inline-start:0} -.pie-none${breakpoint}{padding-inline-end:0} -` - function template({ label, step, direction, value }) { - // Redefine `direction` arg with a formatted version of it, if the arg is truthy - if (direction) direction = `-${direction}` - return `.p${label}${step}${breakpoint}{padding${direction}:${value};}\n` +export default function padding(state = {}) { + const { config = {}, breakpoint = '' } = state + const directionEntries = Object.entries(directions) + const sizes = getCustomProperties(generateSpaceScaleProperties(config.spaceScale)) + + // Null padding + let output = '/*** Padding ***/\n' + output += `.p-none${breakpoint} { padding: 0; }` + directionEntries.forEach(dir => { + output += '\n' + output += `.p${dir[0]}${breakpoint}-none { padding-${dir[1]}: 0; }` + }) + + // Padding scale + if (sizes.length) { + sizes.forEach(size => { + output += '\n' + output += `.p${size.replace('--space-', '')}${breakpoint} { padding: var(${size}); }}` + directionEntries.forEach(dir => { + output += '\n' + output += `.p${dir[0]}${size.replace('--space-', '')}${breakpoint} { padding-${dir[1]}: var(${size}); }` + }) + }) } - output += generateDirectionalVariants({ spaceScale, template }) return output } + diff --git a/v7/classes/custom/radius.mjs b/v7/classes/custom/radius.mjs deleted file mode 100644 index 6fe6abd..0000000 --- a/v7/classes/custom/radius.mjs +++ /dev/null @@ -1,25 +0,0 @@ -export default function radius({ breakpoint = '', radii = [2, 8, 16, 9999] }) { - let output = /*css*/` -/*** Radius ***/ -.radius-none${breakpoint}{border-radius:0;} -.radius-100${breakpoint}{border-radius:100%;} -.radius-pill${breakpoint}{border-radius:9999px;} -.radius-bs-none${breakpoint}, -.radius-is-none${breakpoint}, -.radius-ss-none${breakpoint}{border-start-start-radius:0;} -.radius-bs-none${breakpoint}, -.radius-ie-none${breakpoint}, -.radius-se-none${breakpoint}{border-start-end-radius:0;} -.radius-be-none${breakpoint}, -.radius-is-none${breakpoint}, -.radius-es-none${breakpoint}{border-end-start-radius:0;} -.radius-be-none${breakpoint}, -.radius-ie-none${breakpoint}, -.radius-ee-none${breakpoint}{border-end-end-radius:0;} -` - - radii.map(function(r, i) { - output += `.radius${i}${breakpoint}{border-radius:${r}px;}\n` - }) - return output -} diff --git a/v7/classes/custom/typeface.mjs b/v7/classes/custom/typeface.mjs deleted file mode 100644 index 5a8cd62..0000000 --- a/v7/classes/custom/typeface.mjs +++ /dev/null @@ -1,21 +0,0 @@ -// TODO: ALL OF THIS! -import family from './family.mjs' - -export default function typeface(state = {}) { - const { config = {} } = state - const bodyFontSize = config.typeScale - ? 'var(--text-0)' - : '1rem' - - return /*css*/` -/*** Typeface ***/ -html {font-size: 100%;} -${family(config)} -body { - font-size: ${bodyFontSize}; - font-weight: normal; - line-height: 1; - text-rendering: optimizeSpeed; -} -` -} diff --git a/v7/index.mjs b/v7/index.mjs index 7c000f3..d94c10d 100644 --- a/v7/index.mjs +++ b/v7/index.mjs @@ -1,5 +1,6 @@ import sheetHeader from './lib/sheet-header.mjs' +// Custom properties import borderRadius from './properties/border-radius.mjs' import borderWidths from './properties/border-widths.mjs' import colorScales from './properties/color-scales.mjs' @@ -9,6 +10,15 @@ import fonts from './properties/fonts.mjs' import spaceScale from './properties/space-scale.mjs' import typeScale from './properties/type-scale.mjs' +// Custom classes +import borders from './classes/custom/borders.mjs' +import fontFamily from './classes/custom/font-family.mjs' +import fontSize from './classes/custom/font-size.mjs' +import gap from './classes/custom/gap.mjs' +import grid from './classes/custom/grid.mjs' +import margin from './classes/custom/margin.mjs' +import padding from './classes/custom/padding.mjs' + export default function write(config) { try { @@ -23,7 +33,7 @@ export default function write(config) { } } - // Custom Properties + // Custom properties conditionallyWrite(config.borders.radii, borderRadius) conditionallyWrite(config.borders.widths, borderWidths) conditionallyWrite(config.color.scales, colorScales) @@ -33,6 +43,15 @@ export default function write(config) { conditionallyWrite(config.spaceScale, spaceScale) conditionallyWrite(config.typeScale, typeScale) + // Custom classes + conditionallyWrite(config.borders, borders) + conditionallyWrite(config.fonts, fontFamily) + conditionallyWrite(config.typeScale, fontSize) + conditionallyWrite(config.spaceScale, gap) + conditionallyWrite(config.grid, grid) + conditionallyWrite(config.spaceScale, margin) + conditionallyWrite(config.spaceScale, padding) + return output } catch (err) { diff --git a/v7/lib/getCustomProperties.mjs b/v7/lib/getCustomProperties.mjs new file mode 100644 index 0000000..52232b9 --- /dev/null +++ b/v7/lib/getCustomProperties.mjs @@ -0,0 +1,13 @@ +export default function getCustomProperties(css) { + const lines = css.split('\n') + + const properties = lines + .filter(l => l.includes('--')) // filter to only lines with custom property definitions + .map(l => { + const minified = l.replaceAll(' ', '') // remove all spaces to make substring easier + const property = minified.substring(0, minified.indexOf(':')) // trim to custom property name only + return property + }) + + return properties +} diff --git a/v7/properties/fonts.mjs b/v7/properties/fonts.mjs index 011e823..1156383 100644 --- a/v7/properties/fonts.mjs +++ b/v7/properties/fonts.mjs @@ -1,4 +1,4 @@ -export default function borderRadius(state = {}) { +export default function fonts(state = {}) { const { config = {} } = state const { fonts = { /* DEFAULTS HERE */ } } = config diff --git a/v7/test/fixtures/styleguide.mjs b/v7/test/fixtures/styleguide.mjs index 3da32e5..55d46d4 100644 --- a/v7/test/fixtures/styleguide.mjs +++ b/v7/test/fixtures/styleguide.mjs @@ -34,20 +34,20 @@ export default { steps: 6, }, spaceScale: { - steps: 6, + steps: 3, viewportMin: 320, viewportMax: 1500, baseMin: 16, - baseMax: 18, + baseMax: 24, scaleMin: 'minor-third', scaleMax: 'perfect-fourth', }, typeScale: { - steps: 6, + steps: 3, viewportMin: 320, viewportMax: 1500, baseMin: 16, - baseMax: 18, + baseMax: 24, scaleMin: 'minor-third', scaleMax: 'perfect-fourth', }, diff --git a/v7/test/lib/getCustomProperties.test.js b/v7/test/lib/getCustomProperties.test.js new file mode 100644 index 0000000..b89a599 --- /dev/null +++ b/v7/test/lib/getCustomProperties.test.js @@ -0,0 +1,14 @@ +import borderRadius from '../../properties/border-radius.mjs' +import config from '../fixtures/styleguide.mjs' +import getCustomProperties from '../../lib/getCustomProperties.mjs' +import test from 'tape' + +test('getCustomProperties', t => { + const radii = getCustomProperties(borderRadius({ config })) + t.deepEqual( + radii, + ['--borderRadius-0', '--borderRadius-1'], + 'returns the expected array of custom property names' + ) + t.end() +})