vscode-styled-components icon indicating copy to clipboard operation
vscode-styled-components copied to clipboard

Highlighting breaks when using attrs with props value

Open panda919 opened this issue 3 years ago • 25 comments

**Describe the bug ** I gonna apply attris by pass props. But highlight is broken.

Screenshot

image

Expected behavior HightLight has to be keep

  • OS: [Windows10]
  • VSCode Version: [1.56.0]
  • Extension Version [1.6.1]

Additional context Add any other context about the problem here.

panda919 avatar May 19 '21 16:05 panda919

@panda919 can you please provide some copyable code with this

jasonwilliams avatar May 19 '21 18:05 jasonwilliams

I try it on react native import { View, Text, TextInput, ScrollView } from 'react-native'; `const hPaddingStyle = { paddingHorizontal: Metrics.medium }; const vPaddingStyle = { paddingVertical: Metrics.small }; const hMarginStyle = { marginHorizontal: Metrics.medium }; const vMarginStyle = { marginVertical: Metrics.small }; const fullWidthStyle = { width: '100%' }; // Adapting based on props

export const RootBox = styled.View.attrs(props => ({ style: { ...(props.hPadding && hPaddingStyle), ...(props.vPadding && vPaddingStyle), ...(props.hMargin && hMarginStyle), ...(props.vMargin && vMarginStyle), ...(props.full && fullWidthStyle), ...(props.aspectRatio && { aspectRatio: props.aspectRatio }), ...props.style, }, }))opacity: ${props => props.opacity || 1};;

export const ColumnBox = styled(RootBox)flex-direction: column;;`

panda919 avatar May 20 '21 02:05 panda919

Also breaks with this:

import React from 'react';
import styled from 'styled-components';

const Root = styled.div.attrs(props=>({
  'data-status': `${props.status}`
}))`
  display: block;
  height: 100%;
`;

export default function MyComponent({...props}){
  
  return (
    <Root {...props}>
      <span>Hello world!</span>
    </Root>
  );
}

image

mateusrachid avatar May 21 '21 02:05 mateusrachid

Seems like the problem appears when the argument to the attrs method contains parenthesis.

It breaks with things as simple as:

const MyComponent = styled.div.attrs(({}))` `;
// or
const MyComponent = styled.div.attrs(()=>({}))` `;
// or
const MyComponent = styled.div.attrs((someVar))` `;
// or 
const MyComponent = styled.div.attrs(someFunc())` `;

But does not break with:

const MyComponent = styled.div.attrs(()=>{
  return {};
})` `;

// nor with

const MyComponent = styled.div.attrs(someVar)` `;

mateusrachid avatar May 21 '21 02:05 mateusrachid

At least, I need to apply dynamic style by pass props

panda919 avatar May 21 '21 04:05 panda919

Would someone be able to work on this? We have a contributing guide that’s helpful

jasonwilliams avatar May 21 '21 08:05 jasonwilliams

Honest, I didn;t get this issue on previous versions.

panda919 avatar May 21 '21 09:05 panda919

I have narrowed down the change and found that the bug is introduced since 1.6.0.

I believe it is from #287

There is a pattern for attrs on line 159, but }> was replaced by (?:}>|\\)\\)) on line 7. One thing to notice is that, style syntaxes after .attrs() are colored correctly. However, all styled syntaxes after the one with .attrs() are not colored correctly. I guess all the lines after somehow match line 7 instead of their correct pattern?

I got the purpose of changing line 7 like that, but not sure where to move the new pattern to. Any guide and I may open the PR for this?

PS. my workaround for now is to rollback to version 1.5.2

bluenex avatar May 25 '21 17:05 bluenex

I have narrowed down the change and found that the bug is introduced since 1.6.0.

I believe it is from #287

There is a pattern for attrs on line 159, but }> was replaced by (?:}>|\\)\\)) on line 7. One thing to notice is that, style syntaxes after .attrs() are colored correctly. However, all styled syntaxes after the one with .attrs() are not colored correctly. I guess all the lines after somehow match line 7 instead of their correct pattern?

I'm got the purpose of changing line 7 like that, but not sure where to move the new pattern to. Any guide and I may open the PR for this?

PS. my workaround for now is to rollback to version 1.5.2

Great investigation @bluenex yes I think you’re correct. Out of interest what example code are you using for your observation? It may be worth sharing so we’re seeing the same thing. I don’t know why sometimes line 7 matches without doing a deep dive. Have you looked at the contributions guide or are you already set up?

jasonwilliams avatar May 25 '21 22:05 jasonwilliams

@jasonwilliams I have already set up and ran the test. Here is a snippet to reproduce the behavior and found that the affected code are anything after the component with .attrs() especially JSX. I feel this is a conflict with JSX highlighter? Here is an example of incorrectly colored code that can be reproduced in version 1.6.3:

import React, { useState } from 'react';
import styled, { css } from 'styled-components';

const WithoutAttrs = styled.div`
  /* styled here are colored correctly */
  color: red;
  background-color: white;
  padding: ${(p) => p.color};
`;

const WithoutAttrs2 = styled.div`
  /* styled here are also colored correctly */
  color: red;
  background-color: white;
  padding: ${(p) => p.color};
`;

const WithAttrsWithReturnInCurly = styled.div.attrs(() => {
  return { };
})`
  /* styled here are still colored correctly */
  color: red;
  background-color: white;
  padding: ${(p) => p.color};
`;

const WithAttrsWithShortHandReturn = styled.div.attrs(() => ({ }))`
  /* styled here are still colored correctly */
  color: red;
  background-color: white;
  padding: ${(p) => p.color};
`;

// anything after this is colored incorrectly
// in my case keyword const and especially jsx are not colored correctly
const variable = true;

const NotEvenStyledComponent = () => {
  // non jsx not affected much
  if (variable) {
    console.log('test');
    return undefined;
  }

  return null;
};

const StyledDiv = styled.div`
  /* styles seem to be colored correctly */
  color: red;
  background-color: white;
  padding: ${(p) => p.color};

  ${(p) => p.margin && css`
    margin: 10px ${p.margin}px;
  `}
`;

// following JSX is completely messed up
const SomeSmallComponent = () => (
  <div>
    <h1>This is a demo component</h1>
    <p>this is a demo paragraph</p>
  </div>
);

export default () => {
  const [state, setState] = useState();

  return (
    <StyledDiv>
      <SomeSmallComponent />
      <div>
        <p>Still incorrect</p>
      </div>
    </StyledDiv>
  );
};

Screenshots

1.5.2 1.6.3
image image

bluenex avatar May 26 '21 04:05 bluenex

@bluenex that was super helpful thanks, I should be able to use the same template to reproduce.

the first step would be to see why my last change causes that. It most likely needs removing then adding back in in a more specific way. Then we add a test to capture.

jasonwilliams avatar May 26 '21 08:05 jasonwilliams

@bluenex do you have a conflicting extension? Im not seeing the same issue you are (against master)

image

jasonwilliams avatar May 26 '21 20:05 jasonwilliams

@bluenex do you have a conflicting extension? Im not seeing the same issue you are (against master)

I think you do have the issue. Check the color of const before line 27 and after, they are different color. In the JSX below, the opening tag and closing tag also have different color.

I use GitHub Dark theme so the highlight color is slightly different.

bluenex avatar May 27 '21 02:05 bluenex

@jasonwilliams Please, check the file extension. Obviously, .ts vs .tsx (.js vs .jsx) have different highlighting rules by default.

novli avatar May 27 '21 09:05 novli

@jasonwilliams Please, check the file extension. Obviously, .ts vs .tsx (.js vs .jsx) have different highlighting rules by default.

@novli my issue was the theming not the file extension. It’s very slight but I can see the issue now

jasonwilliams avatar May 27 '21 09:05 jasonwilliams

@bluenex I've made progress by reverting my changes and making a specific block to capture the double parens. A draft PR is open

You will see that with your example above it works. image

The downside is its not perfect and causes issues with this block.

const WithAttrsWithShortHandReturn = styled.div.attrs(() => ({ }))`
  /* styled here are still colored correctly */
  color: red;
  background-color: white;
  padding: ${(p) => p.color};
`;

const StyledButton = styled(({ color1, ...other }) => (
  <Button {...other} classes={{ label: 'label' }} />
))`
  border: 0;
  color: white;
`;

const Root = css<RootProps>`
  height: ${props => (props.label ? 72 : 48)}px;
`;

The third root is not coloured properly. I think because my new addition overrides the meta.arrow.tsx syntax and collides.

jasonwilliams avatar May 28 '21 19:05 jasonwilliams

@bluenex if you wanted to fork my PR its here: https://github.com/styled-components/vscode-styled-components/pull/300

jasonwilliams avatar May 28 '21 19:05 jasonwilliams

Sorry for my late reply. So what is the solution?

panda919 avatar Jul 02 '21 00:07 panda919

Same issue here. Any updates folks? 😊

MultidimensionalLife avatar Jul 03 '21 06:07 MultidimensionalLife

There's no update here, my PR fixes one thing but breaks another. This project doesn't have many contributors so unless you're willing to pitch-in it will just be a case of waiting for someone to find a way through. There's 34 other issues that need attention so I'm unable to dedicate a lot of time to this.

jasonwilliams avatar Aug 10 '21 12:08 jasonwilliams

Wow that's a complicated regex!

I've found this issue crops up now and then for me and in the past I've just ignored it or stopped using attrs and created a wrapper component, which isn't ideal. Thanks to the comments above it seems like a still fairly convenient and readable workaround is just naming the attrs mapping function:

const buttonAttrs = ({ primary }) => ({
  type: primary ? "submit" : "button"
});

const Button = styled.button.attrs(buttonAttrs)`

`;

gpoole avatar May 18 '22 01:05 gpoole

Figured out a work around:

image

const $Text = styled((p: PropsOf<typeof TextField>) => (
  <TextField
    variant="outlined"
    multiline
    placeholder="..."
    InputLabelProps={{ shrink: true }}
    {...p}
  />
))(
  () => css`
    flex-grow: 1;
    margin-top: 1em;
  `
)

Highlighting remains good

nfour avatar Jul 13 '22 10:07 nfour

I played around a little and found another workaround by adding

// `

after a styled component definition like below.

with without

iwan-uschka avatar Sep 06 '22 07:09 iwan-uschka

We just decided to avoid using attrs at all because it causes warnings like this:

Warning: Prop `className` did not match. Server: "sc-hAQmFe fwszIZ" Client: "sc-dkrFOg evlvFY"

After removing/refactoring attrs the warnings disappear. We had some serious trouble with differences between SSR and CSR.

iwan-uschka avatar Feb 22 '23 11:02 iwan-uschka

Still present today and we (as company) cannot decide to remove attrs, unfortunately.

VS Code 1.83.1 Mac Book Pro with M2, 14inch 2023, OS Ventura 13.4.1 vscode-styled-components v1.7.8

Not working

If using () => { } syntax on single or multi-line.

Screenshot 2023-10-16 at 09 57 35

Working 1

If using () => { } as single line or...

Screenshot 2023-10-16 at 09 57 59

Working 2

If using { } syntax, not the () => { } one.

Screenshot 2023-10-16 at 10 08 52

Extra notes

I'm using Palenight Theme and Material Icon Theme for styling my VsCode. I have also Color Highlight and ESLint plugins.

Martinocom avatar Oct 16 '23 08:10 Martinocom