Skip to content

Latest commit

 

History

History
591 lines (523 loc) · 15.2 KB

configuration.mdx

File metadata and controls

591 lines (523 loc) · 15.2 KB

import { Tab, Tabs } from 'nextra-theme-docs';

Config

type IconConfig = {
  disabled?: boolean;
  nodeIds: string[];
  // custom format icon name
  iconName: (nameFromFigma: string) => string;
  exportPath: string;
  // If the field is true, then the SVG sprite will be generated
  generateSprite: boolean;
  // If the field is true, then the file with icons' names as types will be created
  generateTypes: boolean;
  // If the field is true, then the extractor will only generate SVG sprite from local icons
  // else all available icons will be downloaded and the sprile will be generated from them
  localIcons?: boolean;
  // It allows changing svgo config if you need or disable at all
  // if this field is a function, then the function will be run before svgo optimization. And changed config from this function will be passed to svgo optimization
  // if this field is boolean and equals `false` then svgo optimozation won't be run at all
  optimizeSvg?: false | (config?: SVGOConfig) => SVGOConfig;
};

type Config = {
  // your Figma api access key
  apiKey: string;
  // Figma file id
  fileId: string;
  styles: {
    // The main path for exporting all requested data
    exportPath: string;

    /*
      Allowed themes if there is at least one styles field with flag `useTheme`
      It will parse returned name of colors or etc. and look for allowed themes at the start of names
      example: for allowedThemes: ['light','dark'] all returned names will be parsed by looking for 'light' or 'dark' at the start of name
               And if color name is 'light/text/text-900' then it will be transformed to 'text/text-900' and relate to the 'light' theme
               All others name which are not found by allowed themes will be overlooked.
      Note: If there is at least one styles field with flag `useTheme` then this field is required
     */
    allowedThemes?: string[];

    /**
       Default theme for styles fields with flag `useTheme`
       It's used like default variables inside generated CSS variables
       Note: If there is at least one styles field with flag `useTheme` then this field is required
     */
    defaultTheme?: string;
    colors?: {
      disabled?: boolean;
      // custom key name
      keyName?: (name?: string, useTheme?: boolean) => string;
      // Enable using of theme
      useTheme?: boolean;
    };
    gradients?: {
      disabled?: boolean;
      // custom key name
      keyName?: (name?: string) => string;
    };
    effects?: {
      disabled?: boolean;
      // custom key name
      keyName?: (name?: string, useTheme?: boolean) => string;
      // Enable using of theme
      useTheme?: boolean;
    };
    textStyles?: {
      disabled?: boolean;
      // custom key name
      keyName?: (nameFromFigma: string) => string;
      // It allows merging text styles for different screen sizes to a single style
      merge?: boolean;
    };
  };
  // Configuration of icons can have more one setting
  icons: IconConfig | IconConfig[];
  /*
     It's used when textStyles -> merge == true,
     It contains title for each allowed screen size for generation accurate media queries
   */
  screens?: {
    [title: string]: number;
  };
};

Config example:

<Tabs items={['Config with disabled theme', 'Config with enabled theme','Config with multi icons']}>

// @ts-check
const { screens } = require('./theme/screens');

function getKeyName(name) {
  if (name.toLowerCase().startsWith('ui-kit') || name.toLowerCase().startsWith('ui kit')) {
    return 'INTERNAL_DO_NOT_USE';
  }

  /**
   * format name from like:
   *  "heading/h800 - md" ->  "h800-md"
   *  "heading / h800 - md" ->  "h800-md"
   *  "conventions are ignored/heading/h800 - md bla bla" -> "h800-md"
   */
  const resultName = name
    .split('/')
    .at(-1)?
    .replace(' - ', '-')
    .split(' ')
    .find(name => name !== '');

  if (!resultName) {
    throw `getKeyName for "${name}" returns an empty string, check getKeyName implementation`;
  }

  return resultName;
}

const iconNaming = originalName => {
  const formattedName = originalName.replace(/ /g, '').replace('/', '-');
  return formattedName.toLowerCase();
};

/**
* @type {import('@shakuroinc/figma-extractor').Config}
**/
module.exports = {
  apiKey: 'xxxxxx', // your Figma api access key
  fileId: 'xxxxxx', // Figma file id
  styles: {
    exportPath: './theme',
    colors: {
      keyName: getKeyName, // custom key name
    },
    effects: {
      // keyName: nameFromFigma => nameFromFigma, // custom key name
    },
    gradients: {
      // keyName: nameFromFigma => nameFromFigma, // custom key name
    },
    textStyles: {
      keyName: nameFromFigma => `.v-${getKeyName(nameFromFigma)}`,
      merge: true, // or false - it allows merging text styles for different screen sizes to a single style
    },
  },
  icons: {
    // disabled: true,
    nodeIds: ['2310:0', '2090:11', '276:18'],
    iconName: name => iconNaming(name), // custom format icon name
    exportPath: './atoms/icon',
    generateSprite: true,
    generateTypes: true,
    localIcons: false,
  },
  screens: {
    bs: 0,
    ...screens,
  },
};
const screens = {
  sm: '600px',
  md: '979px',
  lg: '1200px',
  xl: '1600px',
};

module.exports = { screens };
```jsx filename="figma-extractor.config.js" copy // @ts-check const { screens } = require('./theme/screens');

function getKeyName(name) { if (name.toLowerCase().startsWith('ui-kit') || name.toLowerCase().startsWith('ui kit')) { return 'INTERNAL_DO_NOT_USE'; }

/**

  • format name from like:
  • "heading/h800 - md" -> "h800-md"
  • "heading / h800 - md" -> "h800-md"
  • "conventions are ignored/heading/h800 - md bla bla" -> "h800-md" */ const resultName = name .split('/') .at(-1)? .replace(' - ', '-') .split(' ') .find(name => name !== '');

if (!resultName) { throw getKeyName for "${name}" returns an empty string, check getKeyName implementation; }

return resultName; }

function getKeyNameWithTheme(name = '') { if (name.toLowerCase().startsWith('ui-kit') || name.toLowerCase().startsWith('ui kit')) { return 'INTERNAL_DO_NOT_USE'; }

const splittedName = name.split('/');

/**

  • format name from like:
  • "dark/heading/h800 - md" -> "h800-md"
  • "dark / heading / h800 - md" -> "h800-md" */ let resultName = splittedName .at(-1) ?.replace(' - ', '-') .split(' ') .find(name => name !== '');

resultName = ${splittedName[0]}/${resultName};

if (!resultName) { throw getKeyNameWithTheme for "${name}" returns an empty string, check getKeyNameWithTheme implementation; }

return resultName; }

const iconNaming = originalName => { const formattedName = originalName.replace(/ /g, '').replace('/', '-'); return formattedName.toLowerCase(); };

/**

  • @type {import('@shakuroinc/figma-extractor').Config} **/ module.exports = { apiKey: 'xxxxxx', // your Figma api access key fileId: 'xxxxxx', // Figma file id styles: { exportPath: './theme', allowedThemes: ['light','dark'], // allowed themes defaultTheme: 'light', // one of the allowed themes which will be meant as default theme colors: { keyName: getKeyNameWithTheme, useTheme: true, }, effects: { keyName: getKeyNameWithTheme, useTheme: true, }, gradients: { // keyName: nameFromFigma => nameFromFigma, // custom key name }, textStyles: { keyName: nameFromFigma => .v-${getKeyName(nameFromFigma)}`, merge: true, // or false - it allows merging text styles for different screen sizes to a single style }, }, icons: { // disabled: true, nodeIds: ['2310:0', '2090:11', '276:18'], iconName: name => iconNaming(name), // custom format icon name exportPath: './atoms/icon', generateSprite: true, generateTypes: true, localIcons: false, }, screens: { bs: 0, ...screens, }, };

```js filename="/theme/screens.js" copy
const screens = {
  sm: '600px',
  md: '979px',
  lg: '1200px',
  xl: '1600px',
};

module.exports = { screens };
If you have black&white and color icons in your project. You might be useful to download all icons through one way.

In this case, you can use such config:

// @ts-check
const { screens } = require('./theme/screens');

function getKeyName(name) {
  if (name.toLowerCase().startsWith('ui-kit') || name.toLowerCase().startsWith('ui kit')) {
    return 'INTERNAL_DO_NOT_USE';
  }

  /**
   * format name from like:
   *  "heading/h800 - md" ->  "h800-md"
   *  "heading / h800 - md" ->  "h800-md"
   *  "conventions are ignored/heading/h800 - md bla bla" -> "h800-md"
   */
  const resultName = name
    .split('/')
    .at(-1)?
    .replace(' - ', '-')
    .split(' ')
    .find(name => name !== '');

  if (!resultName) {
    throw `getKeyName for "${name}" returns an empty string, check getKeyName implementation`;
  }

  return resultName;
}

function getKeyNameWithTheme(name = '') {
  if (name.toLowerCase().startsWith('ui-kit') || name.toLowerCase().startsWith('ui kit')) {
    return 'INTERNAL_DO_NOT_USE';
  }

  const splittedName = name.split('/');

  /**
   * format name from like:
   *  "dark/heading/h800 - md" ->  "h800-md"
   *  "dark / heading / h800 - md" ->  "h800-md"
   */
  let resultName = splittedName
    .at(-1)
    ?.replace(' - ', '-')
    .split(' ')
    .find(name => name !== '');

  resultName = `${splittedName[0]}/${resultName}`;

  if (!resultName) {
    throw `getKeyNameWithTheme for "${name}" returns an empty string, check getKeyNameWithTheme implementation`;
  }

  return resultName;
}

const iconNaming = originalName => {
  const formattedName = originalName.replace(/ /g, '').replace('/', '-');
  return formattedName.toLowerCase();
};

/**
* @type {import('@shakuroinc/figma-extractor').Config}
**/
module.exports = {
  apiKey: 'xxxxxx', // your Figma api access key
  fileId: 'xxxxxx', // Figma file id
  styles: {
    colors: {
      keyName: getKeyNameWithTheme,
    },
    effects: {
      keyName: getKeyNameWithTheme,
    },
    gradients: {
      // keyName: nameFromFigma => nameFromFigma`, // custom key name
    },
    textStyles: {
      keyName: nameFromFigma => `.v-${getKeyName(nameFromFigma)}`,
      merge: true, // or false - it allows merging text styles for different screen sizes to a single style
    },
  },
  icons: [
    // Let's assume this block is used to download black&white icons
    {
      nodeIds: ['2310:0', '2090:11'],
      iconName: name => iconNaming(name), // custom format icon name
      exportPath: './atoms/icon',
      generateSprite: false,
      generateTypes: false,
      localIcons: false,
    },
    // This block is used to download color icons
    {
      nodeIds: ['276:18', '276:21'],
      iconName: name => iconNaming(name), // custom format icon name
      exportPath: './atoms/icon',
      optimizeSvg: false, // For color icons, we must disable svg optimization otherwise downloaded icons will be changed
      generateSprite: false,
      generateTypes: false,
      localIcons: false,
    },
    // And the last block is used to generate a sprite and types
    {
      nodeIds: [],
      exportPath: './atoms/icon',
      generateSprite: true,
      generateTypes: true,
      localIcons: true, // This field is required for this block. It allows working only local icons
    },
  ],
  screens: {
    bs: 0,
    ...screens,
  },
};
const screens = {
  sm: '600px',
  md: '979px',
  lg: '1200px',
  xl: '1600px',
};

module.exports = { screens };

Merging of text styles

The ability to merge text styles by the name's suffix.

Each suffix is one of the defined screen sizes.

Example:

for config:

module.exports = {
  ...
  styles: {
    exportPath: './theme',
    textStyles: {
      ...,
      merge: true,
    },
    ...
  },
  screen: {
    bs: 0, // This is the base screen (default)
    sm: 600,
    md: 900,
    lg: 1200,
  },
  ...
};

Styles like:

- heading/h500 - bs => {fontSize: 12px}
- heading/h500 - sm => {fontSize: 14px}
- heading/h500 - md => {fontSize: 16px}
- heading/h500 - lg => {fontSize: 20px}

will be transformed:

"heading/h500": {
  fontSize: '12px',
  '@media (min-width: 600): {
    fontSize: '14px',
  },
  '@media (min-width: 900): {
    fontSize: '16px',
  },
  '@media (min-width: 1200): {
    fontSize: '20px',
  },
}

Themes for colors and effects

If the colors or effects field has useTheme: true then CLI will look for allowed themes and creates colors or effects according to such themes.

  • allowedThemes - list of the allowed themes. By only these themes, it will be generated particular files.
  • defaultTheme - one of the allowed themes. Default variables for CSS variables will be taken from this theme.

Example:

for config:

module.exports = {
  ...
  allowedThemes: ['light','dark','blue'],
  defaultTheme: 'blue',
  styles: {
    exportPath: './theme',
    colors: {
      ...,
      useTheme: true,
    },
    ...
  },
  ...
};

The CLI will generate such files:

export const DEFAULT_THEME = 'blue';

export const THEMES = ['light', 'dark', 'blue'];

export type Theme = typeof THEMES[number];
module.exports = {
    "text-txt600":"#000000",
    "text-txt700":"#000000",
    "text-txt800":"#000000",
    "text-txt900":"#000000",
};
module.exports = {
    "text-txt600":"#ffffff",
    "text-txt700":"#ffffff",
    "text-txt800":"#ffffff",
    "text-txt900":"#ffffff",
};
module.exports = {
    "text-txt600":"#0000ff",
};
module.exports = {
    "text-txt600":"#0000ff", // it will be taken from a default theme if it is defined for a specific color
    "text-txt700":"",
    "text-txt800":"",
    "text-txt900":"",
};
module.exports = {
    "text-txt600":"var(--sh-text-txt600,'#0000ff')", // it will be taken from a default theme if it is defined for a specific color
    "text-txt700":"var(--sh-text-txt700,'')",
    "text-txt800":"var(--sh-text-txt800,'')",
    "text-txt900":"var(--sh-text-txt900,'')",
};
[data-theme='dark'] {
    --sh-text-txt600: #000000;
    --sh-text-txt700: #000000;
    --sh-text-txt800: #000000;
    --sh-text-txt900: #000000;
}
[data-theme='light'] {
    --sh-text-txt600: #ffffff;
    --sh-text-txt700: #ffffff;
    --sh-text-txt800: #ffffff;
    --sh-text-txt900: #ffffff;
}
[data-theme='blue'] {
    --sh-text-txt600: #0000ff;
}
/* from blue theme due to it is a default theme */
:root {
    --sh-text-txt600: #ff00ff;
    --sh-text-txt700: '';
    --sh-text-txt800: '';
    --sh-text-txt900: '';
}

Also, the same files will be generated for useTheme inside effects section.