Git Product home page Git Product logo

design-lint's Introduction

Design Lint

Design Lint Gif Example

Find and fix errors in your designs with Design Lint, a plugin for Figma.

View Plugin Page

Design Lint finds missing styles within your designs on all your layers. Ensure your designs are ready for development or design collaboration by fixing inconsistencies.

While it's running, Design Lint will update automatically as you fix errors. Clicking on layer will also select that layer in your design. Navigating between each error is fast and much easier than trying to find errors on your own.

Features

  • Selecting a layer with an error will also select the layer in Figma, letting you navigate your page and fix errors with full context.
  • Design Lint polls for changes and will update as you fix errors.
  • "Ignore" or "Ignore All" buttons let you skip special layers.
  • Use the "Select All" option to fix multiple errors at once that share the same value.
  • Need to skip layers like illustrations? Locked layers in Figma will be skipped from linting.
  • Custom border radius values can be set within settings and are stored in Client Storage.

Design Lint Ignore Example

Design Lint Selection Example

Because Design Lint doesn't try and manage your library, there's no logging in, accounts, or syncing. This open source plugin is designed to make fixing errors easy and let you get back to designing. Want to write specific rules for your own organization? Feel free to fork this repo and edit to your liking!

Install from the Figma Plugin Page

Although this plugin is open source, for most users you'll want to install from the Figma plugin community page. View Plugin Page

To Run Locally use following commands

  • Run yarn to install dependencies.
  • Run yarn build:watch to start webpack in watch mode.

To Edit it

The react code, components, and UI can be found here App.tsx.
The Figma API, Storage, and Linting happens in controller.ts. Linting functions and rules can be found in lintingFunctions.ts.

How the Linting Works

Different layers (referred to as Nodes in the Figma API) have different properties to lint. First we loop through the layers the user has selected. For each layer we determine that layers type.

function determineType(node) {
    switch (node.type) {
      case "SLICE":
      case "GROUP": {
        // Groups styles apply to their children so we can skip this node type.
        let errors = [];
        return errors;
      }
      case "CIRCLE":
      case "VECTOR":
      case "STAR":
      case "BOOLEAN_OPERATION":
      case "SQUARE": {
        return lintShapeRules(node);
      }
      case "FRAME": {
        return lintFrameRules(node);
      }
      case "INSTANCE":
      case "RECTANGLE": {
        return lintRectangleRules(node);
      }
      case "COMPONENT": {
        return lintComponentRules(node);
      }
      case "TEXT": {
        return lintTextRules(node);
      }
      case "LINE": {
        return lintLineRules(node);
      }
      default: {
        // Do nothing
      }
    }
  }

Some of these node types have the same requirements so there are generic functions that call multiple linting functions which are imported from lintingFunctions.ts.

function lintTextRules(node) {
    let errors = [];

    checkType(node, errors);
    checkFills(node, errors);
    checkEffects(node, errors);
    checkStrokes(node, errors);

    return errors;
  }

So for instance, this function runs the linting rules for typography, fills, effects, and strokes on this layer since its a piece of text, and text layers have all those properties. Where as a Frame only lints for fills, effects, and strokes, as it can't have any type styles.

What does Design Lint check for by default?

Out of the box, Design Lint only checks for layers that are not using styles. In Figma, best practice is to use styles (also referred to as design tokens) on all of your layers, so your type, colors, spacing etc are all consistent.

That being said, Design Lint is ready for you to write custom rules for your team. For example, if you wanted to ensure that no text layers are using background specific colors, you could check for this, an example is provided below.

Error Array

Design Lint references one array of all the errors returned by the lint rules. Each error in the array is an object. A given layer in Figma can have multiple errors, let's say it's missing both a text style and using an incorrect fill color, so we use that layers unique ID (set by Figma) to identify which errors belong to it.

Error Object

When a linting function runs and finds an error, we return an error object. This object has the original nodes information, it's ID (which we use to select it), it's name, what kind of layer it is, etc. When writing a custom error, you can customize the messages it returns. Node and type (fill, text, effect, stroke, or radius) are required.

  return errors.push(
    createErrorObject(
      node, // Node object we use to reference the error (id, layer name, etc)
      "fill", // Type of error (fill, text, effect, etc)
      "Missing Text Style", // Large text to indicate what the error is.
      "Multiple Styles" // Some linting functions use another function here to return a fill HEX value or a number.
    )
  );

Writing Custom Rules

Until I have time to write a formal tutorial, I've added a placeholder linting function with comments that will guide you through creating some basic custom rules for your design team.

// Custom Lint rule that isn't being used yet!
// that ensures our text fills aren't using styles (design tokens) meant for backgrounds.
export function customCheckTextFills(node, errors) {
  // Here we create an array of style keys (https://www.figma.com/plugin-docs/api/PaintStyle/#key)
  // that we want to make sure our text layers aren't using.

  const fillsToCheck = [
    "4b93d40f61be15e255e87948a715521c3ae957e6"
    // To collect style keys, use a plugin like Inspector, or use console commands like figma.getLocalPaintStyles();
    // in your design system file.
  ];

  let nodeFillStyle = node.fillStyleId;

  // If there are multiple text styles on a single text layer, we can't lint it
  // we can return an error instead. If this were a frame, rectangle, or other layer type, we could remove this check.
  if (typeof nodeFillStyle === "symbol") {
    return errors.push(
      createErrorObject(
        node, // Node object we use to reference the error (id, layer name, etc)
        "fill", // Type of error (fill, text, effect, etc)
        "Mixing two styles together", // Message we show to the user
        "Multiple Styles" // Normally we return a hex value here
      )
    );
  }

  // We strip the additional style key characters so we can check
  // to see if the fill is being used incorrectly.
  nodeFillStyle = nodeFillStyle.replace("S:", "");
  nodeFillStyle = nodeFillStyle.split(",")[0];

  // If the node (layer) has a fill style, then check to see if there's an error.
  if (nodeFillStyle !== "") {
    // If we find the layer has a fillStyle that matches in the array create an error.
    if (fillsToCheck.includes(nodeFillStyle)) {
      return errors.push(
        createErrorObject(
          node, // Node object we use to reference the error (id, layer name, etc)
          "fill", // Type of error (fill, text, effect, etc)
          "Incorrect text color use", // Message we show to the user
          "Using a background color on a text layer" // Determines the fill, so we can show a hex value.
        )
      );
    }
    // If there is no fillStyle on this layer,
    // check to see why with our default linting function for fills.
  } else {
    checkFills(node, errors);
  }
}

Import your function in controller.ts

Once you've written some custom functions for checking specific rules, make sure to import your function here in the controller.ts file.

Let's say we've written a custom rule for text layers, make sure to change what functions run for text layers here under the lintTextRules function.

Changing the border radius default

If you plan on using this app as a private plugin you'll likely want to change the default border radius values which are [0, 2, 4, 8, 16, 24, 32]. This can be acheived by changing these values in App.tsx and in controller.ts.

Tooling

This repo is using following:

design-lint's People

Contributors

akash-123-svg avatar alexjlockwood avatar dependabot[bot] avatar destefanis avatar ertrzyiks avatar isakshamgupta avatar pchr-srf avatar websiddu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

design-lint's Issues

Found a bug in `traverseNodes` usage in controller.ts

Specifically here: https://github.com/destefanis/design-lint/blob/master/src/plugin/controller.ts#L133-L149

  let nodes = traverseNodes(figma.currentPage.selection);

  // Traverses the node tree
  function traverse(node) {
    if ("children" in node) {
      if (node.type !== "INSTANCE") {
        for (const child of node.children) {
          traverse(child);
        }
      }
    }
    return node;
  }

  function traverseNodes(selection) {
    let traversedNodes = traverse(selection);

    return traversedNodes;
  }

traverse(node) expects a single SceneNode object. However, you are passing an array of SceneNodes to traverseNodes(selection) which then passes an array of SceneNodes to traverse(). I assume this must be a type bug.

Configuration File?

Heyo,

my designers have pointed me towards DesignLint. I think it is a great tool. Something very similar that we know from eslint and alike. If I'm not mistaken, I would go fork it and make it available for my team with our "business" design rules.

I was wondering, if that can be can be configurable instead, similar to how eslint can be configured with a config file. Such a configuration file can be hosted somewhere accessible to designlint in a static form (json over js) to describe the rules. Bonus points to use them same rules in stylelint.

What's the idea on that?

Random error messages pop up

Hi there,

I'm very sorry not being able to be more specific but when using the plugin (which is great!) from time to time error messages like this appear at the bottom of Figma's window:

Bildschirmfoto 2023-02-06 um 12 57 35

When opening the console this can be read:

Bildschirmfoto 2023-02-06 um 12 59 12

Afterwards, using other plugins is also likely to produce error messages of various kinds. Restarting the Figma app solves the problem (obviously).

I'm aware that all this is quite vage but I haven't found a pattern yet that causes all this. Can you read something useful from it nonetheless?

If you want me to send specific information, I'd be happy to help. As said before, the plugin is great!

[Suggestions] Mega List

Hi! In order to keep suggestions centralized, I'm going to keep this issue open and have people share their ideas here.

Ideas:

  • Check type for contrast
  • Allow a toggle to ignore remote libraries from linting

Project Initialisation

Hey @destefanis I absolutely loved the idea of Design Lint.

In the end of the README you are saying

Changing the border radius default
If you plan on using this app as a private plugin you'll likely want to change the default border radius values which are [0, 2, 4, 8, 16, 24, 32]. This can be acheived by changing these values in App.tsx and in controller.ts.

People and especially designers are going to use it out of the box, so wouldn't be great to set their own best practices or even "scan" their established Figma project and initialise their own design styles?

Error: Unable to load code: Error in Development mode

Hi,

I’m having issues running my plugin locally in development.

The verbose I get in the console sheds no light on what the issue is.

the first yarn install verboses throws the following warnings:

❯ yarn
yarn install v1.22.19
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
[1/2] ⠐ fsevents
warning Error running install script for optional dependency: "/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents: Command failed.
Exit code: 1
Command: node install
Arguments:
Directory: /Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents
Output:
node-pre-gyp info it worked if it ends with ok
node-pre-gyp info using [email protected]
node-pre-gyp info using [email protected] | darwin | arm64
node-pre-gyp WARN Using needle for node-pre-gyp https download
node-pre-gyp info check checked for \"/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents/lib/binding/Release/node-v108-darwin-arm64/fse.node\" (not found)
node-pre-gyp http GET https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.2.9/fse-v1.2.9-node-v108-darwin-arm64.tar.gz
node-pre-gyp http 404 https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.2.9/fse-v1.2.9-node-v108-darwin-arm64.tar.gz
node-pre-gyp WARN Tried to download(404): https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.2.9/fse-v1.2.9-node-v108-darwin-arm64.tar.gz
node-pre-gyp WARN Pre-built binaries not found for [email protected] and [email protected] (node-v108 ABI, unknown) (falling back to source compile with node-gyp)
node-pre-gyp http 404 status code downloading tarball https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.2.9/fse-v1.2.9-node-v108-darwin-arm64.tar.gz
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | darwin | arm64
gyp info ok
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | darwin | arm64
gyp info find Python using Python version 3.9.6 found at \"/Applications/Xcode.app/Contents/Developer/usr/bin/python3\"
gyp info spawn /Applications/Xcode.app/Contents/Developer/usr/bin/python3
gyp info spawn args [
gyp info spawn args   '/Users/scharbaux/.nvm/versions/node/v18.14.2/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args   'binding.gyp',
gyp info spawn args   '-f',
gyp info spawn args   'make',
gyp info spawn args   '-I',
gyp info spawn args   '/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents/build/config.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/Users/scharbaux/.nvm/versions/node/v18.14.2/lib/node_modules/npm/node_modules/node-gyp/addon.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/Users/scharbaux/Library/Caches/node-gyp/18.14.2/include/node/common.gypi',
gyp info spawn args   '-Dlibrary=shared_library',
gyp info spawn args   '-Dvisibility=default',
gyp info spawn args   '-Dnode_root_dir=/Users/scharbaux/Library/Caches/node-gyp/18.14.2',
gyp info spawn args   '-Dnode_gyp_dir=/Users/scharbaux/.nvm/versions/node/v18.14.2/lib/node_modules/npm/node_modules/node-gyp',
gyp info spawn args   '-Dnode_lib_file=/Users/scharbaux/Library/Caches/node-gyp/18.14.2/<(target_arch)/node.lib',
gyp info spawn args   '-Dmodule_root_dir=/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents',
gyp info spawn args   '-Dnode_engine=v8',
gyp info spawn args   '--depth=.',
gyp info spawn args   '--no-parallel',
gyp info spawn args   '--generator-output',
gyp info spawn args   'build',
gyp info spawn args   '-Goutput_dir=.'
gyp info spawn args ]
gyp info ok
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | darwin | arm64
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
  SOLINK_MODULE(target) Release/.node
  CXX(target) Release/obj.target/fse/fsevents.o
In file included from ../fsevents.cc:6:
../../nan/nan.h:2536:8: warning: 'SetAccessor' is deprecated: Do signature check in accessor [-Wdeprecated-declarations]
  tpl->SetAccessor(
       ^
/Users/scharbaux/Library/Caches/node-gyp/18.14.2/include/node/v8-template.h:837:3: note: 'SetAccessor' has been explicitly marked deprecated here
  V8_DEPRECATED(\"Do signature check in accessor\")
  ^
/Users/scharbaux/Library/Caches/node-gyp/18.14.2/include/node/v8config.h:460:35: note: expanded from macro 'V8_DEPRECATED'
# define V8_DEPRECATED(message) [[deprecated(message)]]
                                  ^
In file included from ../fsevents.cc:6:
In file included from ../../nan/nan.h:2884:
../../nan/nan_typedarray_contents.h:34:43: error: no member named 'GetContents' in 'v8::ArrayBuffer'
      data   = static_cast<char*>(buffer->GetContents().Data()) + byte_offset;
                                  ~~~~~~~~^
1 warning and 1 error generated.
make: *** [Release/obj.target/fse/fsevents.o] Error 1
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/Users/scharbaux/.nvm/versions/node/v18.14.2/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:203:23)
gyp ERR! stack     at ChildProcess.emit (node:events:513:28)
gyp ERR! stack     at ChildProcess._handle.onexit (node:internal/child_process:291:12)
gyp ERR! System Darwin 22.3.0
gyp ERR! command \"/Users/scharbaux/.nvm/versions/node/v18.14.2/bin/node\" \"/Users/scharbaux/.nvm/versions/node/v18.14.2/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js\" \"build\" \"--fallback-to-build\" \"--module=/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents/lib/binding/Release/node-v108-darwin-arm64/fse.node\" \"--module_name=fse\" \"--module_path=/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents/lib/binding/Release/node-v108-darwin-arm64\" \"--napi_version=8\" \"--node_abi_napi=napi\" \"--napi_build_version=0\" \"--node_napi_label=node-v108\"
gyp ERR! cwd /Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents
gyp ERR! node -v v18.14.2
gyp ERR! node-gyp -v v9.3.1
gyp ERR! not ok
node-pre-gyp ERR! build error
node-pre-gyp ERR! stack Error: Failed to execute '/Users/scharbaux/.nvm/versions/node/v18.14.2/bin/node /Users/scharbaux/.nvm/versions/node/v18.14.2/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --module=/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents/lib/binding/Release/node-v108-darwin-arm64/fse.node --module_name=fse --module_path=/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents/lib/binding/Release/node-v108-darwin-arm64 --napi_version=8 --node_abi_napi=napi --napi_build_version=0 --node_napi_label=node-v108' (1)
node-pre-gyp ERR! stack     at ChildProcess.<anonymous> (/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents/node_modules/node-pre-gyp/lib/util/compile.js:83:29)
node-pre-gyp ERR! stack     at ChildProcess.emit (node:events:513:28)
node-pre-gyp ERR! stack     at maybeClose (node:internal/child_process:1091:16)
node-pre-gyp ERR! stack     at ChildProcess._handle.onexit (node:internal/child_process:302:5)
node-pre-gyp ERR! System Darwin 22.3.0
node-pre-gyp ERR! command \"/Users/scharbaux/.nvm/versions/node/v18.14.2/bin/node\" \"/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents/node_modules/node-pre-gyp/bin/node-pre-gyp\" \"install\" \"--fallback-to-build\"
node-pre-gyp ERR! cwd /Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents
node-pre-gyp ERR! node -v v18.14.2
node-pre-gyp ERR! node-pre-gyp -v v0.12.0
node-pre-gyp ERR! not ok
Failed to execute '/Users/scharbaux/.nvm/versions/node/v18.14.2/bin/node /Users/scharbaux/.nvm/versions/node/v18.14.2/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --module=/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents/lib/binding/Release/node-v108-darwin-arm64/fse.node --module_name=fse --module_path=/Users/scharbaux/Documents/AgodaGit/ads-lint/node_modules/fsevents/lib/binding/Release/node-v108-darwin-arm64 --napi_version=8 --node_abi_napi=napi --napi_build_version=0 --node_napi_label=node-v108' (1)"
✨  Done in 59.98s.

Note:

I’ve had to add export SET NODE_OPTIONS=--openssl-legacy-provider to the yarn build:watch script command to allow it to build Webpack for arm-64 M1 chips, instead of x84-64 by default with node 18.

This is the error I’m getting when importing the plugin’s manifest and executing it In Development mode:
image

I’ve looked at the minified files and couldn’t find much clarity besides a vague error message regarding the manifest, but it seem to work just fine on the Published version so I don’t think there should be anything missing there.

The issue seem to only happen on my M1 Max, but runs just fine on my M1 Pro. I’ve tried uninstalling Figma completely (using the available uninstall.sh on Figma’s website), I’ve completely removed nodejs and reinstalled cleanly with nvm, but the issue still persists, making it impossible for me to run the plugin on this machine... 🤷‍♂️

On the other hand, the New Plugin template (that creates 5 rectangles) generated through the Figma app does run just fine in development mode on this machine.

My dev env:
Apple M1 Max Ventura 13.2.1
node v18.4.2
yarn v1.22.19
xcode-select v2396

Any guidance on where I should be looking to debug this issue would be greatly appreciated. 🙏😄

Bug when clicking 'Re-run' and 'Jump to next error' with a single active error

Here is a video showing how to reproduce: https://youtu.be/WbOxTZhbiRU

  1. Select a layer with a single lint error
  2. Open design lint
  3. Click 'Re-run'
  4. Click 'Jump to next error'
  5. Close the side panel

The expected behavior is that the empty state view should not be shown (the node list should still be shown instead).

I believe the issue is here: https://github.com/destefanis/design-lint/blob/7c4290d8ab7d22d57a1a758a17974c97a2c54e80/src/app/components/App.tsx

This code needs to someething like this:

setActiveNodeIds(activeNodeIds => {
    return activeNodeIds.includes(nodes[0].id)
        ? activeNodeIds
        : [...activeNodeIds, nodes[0].id];
});

Because otherwise the list of active node IDs will contain duplicate IDs (which is what ends up triggering the bug).

Found a lineHeight bug in checkType() linting function

The current implementation is as follows:

export function checkType(node, errors) {
  if (node.textStyleId === "" && node.visible === true) {
    let textObject = {
      font: "",
      fontStyle: "",
      fontSize: "",
      lineHeight: {}
    };

    textObject.font = node.fontName.family;
    textObject.fontStyle = node.fontName.style;
    textObject.fontSize = node.fontSize;
    textObject.lineHeight = node.lineHeight.value;

    let currentStyle = `${textObject.font} ${textObject.fontStyle} / ${textObject.fontSize} (${textObject.lineHeight} line-height)`;

    return errors.push(
      createErrorObject(node, "text", "Missing text style", currentStyle)
    );
  } else {
    return;
  }
}

According to the most recent figma.d.ts file, the declaration of a text node's line height is:

type LineHeight =
    | {
          readonly value: number;
          readonly unit: 'PIXELS' | 'PERCENT';
      }
    | {
          readonly unit: 'AUTO';
      };

The problem is that textNode.lineHeight.value; will return undefined when the lineHeight.unit is equal to AUTO. The way I've updated the function in our internal fork of this repo is as follows:

export interface LintError {
  readonly node: SceneNode;
  // TODO: make this type more explicit?
  readonly type: string;
  readonly message: string;
  readonly value: string;
}

export function checkType(node: TextNode, errors: LintError[]) {
  const { fontName, lineHeight, fontSize } = node;
  if (
    fontName !== figma.mixed &&
    lineHeight !== figma.mixed &&
    fontSize !== figma.mixed &&
    node.textStyleId === '' &&
    node.visible
  ) {
    const fontFamily = fontName.family;
    const fontStyle = fontName.style;
    const lineHeightValue = lineHeight.unit === 'AUTO' ? 'AUTO' : lineHeight.value.toString();
    const currentStyle = `${fontFamily} ${fontStyle} / ${fontSize} (${lineHeightValue} line-height)`;
    errors.push(createErrorObject(node, 'text', 'Missing text style', currentStyle));
  }
}

Ignored errors can clash across different Figma files if nodes happen to share the same ID

Currently ignored lint errors are identified by the node.id associated with it. However, node IDs are only guaranteed to be unique within the current Figma file, which can cause problems.

For example, say you are in one Figma file and you ignore an error on a TextNode with a string ID 1:2. Then you jump into a second Figma file, and you run lint on a TextNode that just happens to also have the same lint error as well as the same ID 1:2.

Because the ignored errors are stored in local storage, the lint error in the 2nd file will not display because a very similar case just happened to be ignored in the first file.

I think maybe one possible way to address this issue is to store ignored errors on the nodes themselves using setPluginData(). (Just an idea... haven't totally thought it through yet but seemed like it might be promising).

Errors resolving without being solved.

Just had this issue, where a bunch of errors were found, then when I jump to the first error, they all magically resolve. I don't have any rules ignored in settings. They are on instances of components if that matters at all.

Screen-Recording-2020-01-30-at-09 02 58

Linting figma tokens

Just found your plugin. We actually just started building something similar, but with the goal to:

Check all components, layer by layer and verify if all values that can be a figma token are set.

All values that are not set with a token, show the nearest matching tokens and option to apply missing tokens easily.

Convert all styles to matching tokens.

I'm hoping something on these lines has already been created, if not, with some guidance we'd be happy to contribute this functionality. I thi k this makes a lot of sense for many teams.

Update dev dependencies

Hi, in my fork I recently updated most of the dev dependencies like webpack, prettier, typescript etc to their latest versions. I can contribute it back and submit a PR if you are interested in merging such a change.

Idea for Improvement

Hi Daniel
Thank you for sharing your plugin.

I started to use that on my daily process and I faced some "process" problems. But first, I would like to give some background information, so you will know more details.

Use Case: I want to check only the local components. To organize everything we are using another library https://www.figma.com/c/file/788676139164058166 and there I have some issues. Can I have some kind of checkbox or ability to ignore all components from a specific library? So I can lint designs for the library that I'm working on right now?

Suggestion: There are two touchpoints for this feature. The one on the "review" screen. We can add a menu icon with drop-down options like "ignore component" or "ignore library". Here is the preview https://tppr.me/Rkbec and the second touchpoint on the settings page. Where I can add connected libraries as ignored.

If you would like to have a quick call, here is my calendly.com/faridsabitov. Thank you for helping the design community!

All the best,
Farid

Missing strokes/effects linting function warns about unlinked strokes/effects that are invisible

The fills linting function ignores unlinked fills that are not visible (i.e. !fills[0].visible).

https://github.com/destefanis/design-lint/blob/master/src/plugin/lintingFunctions.ts#L187

I noticed that the strokes and effects linting functions do not follow this same logic. Seemed like it could be a bug?

I also noticed that the checkEffects() function doesn't currently check if the node is visible or not (unlike the checkType, checkFills, and checkStrokes functions).

Avoid running auto-refresh when Figma file is in the background

The plugin currently auto-refreshes in the background, even when Figma is minimized or a different Figma file tab is being used.

In addition to triggering auto-refresh when the window state changes from 'focus' to 'blur', I found it useful to also take the document's visibility into account as well (i.e. don't auto-refresh when document.hidden is true): https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.