Giter Club home page Giter Club logo

container-query's People

Contributors

greenkeeper[bot] avatar zeecoder 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

container-query's Issues

Support css-loader modules in webpack (via a new *-loader)

Webpack's css-loader has the modules option, which renames all classnames to a unique hash.

Problem is, when the transpilation process is:
source CSS => PostCSS plugins => container query => css-loader

Then the container query stats json will have the original classnames instead of the new hashed ones, and it won't work.

The solution could be adding a mapping function to the runtime, which would rename all classnames to the new ones based on the classname map the loader returns:

const styles = require('./Button.pcss');
const containerStatsJSON = require('./Button.pcss.json')['.Button'];
mapClassesToHashes(containerStatsJSON, styles);

Support "not" before queries

This would not work as expected right now:
@container (height > 100px) and (width > 100px), not (orientation: landscape)

Automated test in real browsers

To make sure supported browsers are truly supported, tests should run in different environments automatically.
Maybe saucelabs or browserstack.

Only apply styles when necessary

Currently on each adjust() call a style object is created based on the queries and container units, then it's applied.

This could be cached, however, so that the same styles are not applied if nothing changed since the last adjust() call.

When there's no container units used for a container, the benefits would be even greater, since then it's even more unlikely that a new style object is needed on every adjust() call.

@zeecoder/react-container-query

The following HOC will save us some time:

export const ContainerQuery = (WrappedComponent, stats, opts = {}) =>
  class extends Component {
    componentDidMount() {
      new Container(ReactDOM.findDOMNode(this), stats, opts);
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };

Turn to a monorepo

Packages would be then:

  • @zeecoder/container-query => the runtime Container class
  • @zeecoder/postcss-container-query => the postcss plugin

Future packages could then also be included, like:

  • @zeecoder/react-container-query

Support unitless value generation

Right now ch / cw units are used to generate real css units:
chpx / cwpx => px
chem / cwem => em
etc

But it would be useful to generate unitless values, like for opacity and rgb.
It cannot however just be ch / cw, since ch is already reserved by CSS.

singleContainer option

... or something similar, because doing this in a react component is annoying:

image

Idea: If singleContainer is set, then the postcss plugin should expect a single container only.
This means that the resulting JSON would not have string keys with the container selectors, but rather would be the stat for that single container in the processed css source.

If more than one @define-container is encountered, add a warning, and return with the first container found.

Container queries are unitless

The expect @container (width > 200px) doesn't work, only if you write @container (width > 200);

The unit should be included.

Edge case: rules not applied in the right order

Consider the following CSS:

.Block {
  background: black;

  @condition (width >= 100px) {
    background: green;
  }

  &--blue {
    @condition (width >= 100px) {
      background: blue;
    }
  }
}

Assuming there's a .Block and .Block .Block--blue element, both buttons will switch to green if wider than 100px.
This is because as the algorithm resolves the styles, it get's to the following query in the JSON:

{
    "selector": ".Block",
    "queries": [{
        "conditions": [
            [
                ["width", ">=", 100]
            ]
        ],
        "elements": [{
            "selector": ".Block",
            "styles": {
                "background": "green"
            }
        }]
    }{
        "conditions": [
            [
                ["width", ">=", 100]
            ]
        ],
        "elements": [{
            "selector": ".Block--blue",
            "styles": {
                "background": "blue"
            }
        }]
    }]
}

Since the algorithm resolves from back-to-front, it'll first apply .Block--blue's, then .Block's styles.

That's how the green background gets applied last.

Improve browser support

Browser support seems to be quite poor:

  • Chrome > 50
  • Firefox > 50
  • Opera > 38
  • Safari > 9.1
  • No IE
  • No Edge

For starters, Object.assign needs to be polyfilled.

Look into comment issues

Comments are not handled well, and cause transpile errors.
Look into what exactly causes them.

Non-@container at-rules are being processed

This:

@keyframes Expand{
    0%{
        transform: scale(1);
        opacity: 1;
    }
    25%{
        opacity: 1;
    }
    50%, 100%{
        transform: scale(2);
        opacity: 0;
    }
}

Produces something like this, in the JSON:

{
    "selector": ".Expand.Two",
    "styles": {}
}, {
    "selector": ".Expand.Three",
    "styles": {}
}, {
    "selector": "from",
    "styles": {}
}, {
    "selector": "to",
    "styles": {}
}, {
    "selector": "0%",
    "styles": {}
}, {
    "selector": "25%",
    "styles": {}
}, {
    "selector": "50%, 100%",
    "styles": {}
}

Which breaks things.

Allow one `@define-container;` declaration in singleContainer mode

The default mode for the postcss plugin is singleContainer: true, which means that the plugin automatically detects the first class it encounters as the container class.

A single @define-container; declaration should be allowed in these cases, however, if the container class is not the first in the file.

(More than one @define-container; occurrences should still throw an error though.)

Measure and improve performance

Performance was not particularly a focus for the 1.0.0 release, but it should be measured nonetheless.

Also: Compare the current implementation with one that would inject styles in <style> tags to see if that would be more performant. (Possible 2.0.0 feature?)

Supporting nested containers better

The following code confuses the plugin, since it doesn't detect the boundaries between nested containers:

div {
    & > div { background-color: green; }

    @container (width > 200px) {
        & > div { background-color: red; }
    }
}
<div>
<div>
<div>
</div>
</div>
</div>

Revisit polyfilling

It might worth reconsidering the polyfilling issue.
Originally I shipped all necessary polyfills to make it easier to adapt the library, but that comes with some cons:

  • Shipping the polyfill adds extra weight to the lib
  • If the polyfill is applied automatically, then that could be applied before the app developer applies its own polyfill => this could result in hard to debug situations, where this lib would polyfill something sooner than the app developer.

Using something like polyfill.io, or just a separate polyfill js file made by the app author should be an easy enough thing to do, since I'm already assuming a lot of knowledge with these modules anyway.

Anyway, needs some more research into polyfilling best practices.

An in-range update of prettier is breaking the build 🚨

Version 1.3.0 of prettier just got published.

Branch Build failing 🚨
Dependency prettier
Current Version 1.2.2
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As prettier is β€œonly” a devDependency of this project it might not break production or downstream projects, but β€œonly” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this πŸ’ͺ

Status Details - ❌ **continuous-integration/travis-ci/push** The Travis CI build failed [Details](https://travis-ci.org/ZeeCoder/container-query/builds/228141087?utm_source=github_status&utm_medium=notification)

Release Notes 1.3.0

Facebook Adoption Update

The reason why I (@vjeux) embarked on this journey working on prettier has always been to get the entire Facebook codebase converted over. I would like to give an update on how it is going and what is the process to get there.

The first projects to adopt prettier were Jest, React and immutable-js. Those are small codebases in the order of hundreds of files that have their own infrastructure. There are 5 or less people working on them full time.

Then, Oculus and Nuclide converted their codebase over. The scale is bigger with a few thousands of files and tens of full time contributors but looks pretty similar to the first projects. The conversions went in one big codemod and that's it.

Now, the entire Facebook codebase is way bigger than this and it's not feasible to just convert everything in one go and to convince everyone that their entire codebase is going to be reformatted under their feet. So we need to find a more incremental approach.

Scaling adoption

Running prettier on a piece of code is a pretty expensive operation, it makes your pull request look bad because of a lot of unrelated changes and it causes merge conflicts for all the outstanding pull requests. So once a file has been formatted, you should do everything to make sure it remains formatted.

  • When pretty-printing a file, add @format to the first block comment like @flow.
  • Have a lint rule with autofix that checks if the file is correctly pretty printed when @format is present.
    • When running Nuclide, it's going to show as an inline warning and have a fix button.
    • When sending a pull request, it's going to show the lint failing with a [Yn] prompt that you can just press enter.
  • Update the default code templates to add @format to the header.
  • When you run code formatting via cmd-shift-c inside of Nuclide, automatically insert the @format header.
  • Disable all the stylistic rules like max-len when @format is in the header.
  • Have script to run prettier through an entire folder with everything configured as a one line operation.
  • Have a good guide to help people that want to convert their codebase over with instructions and best practices.
  • When pushing a new release of prettier, also run it through all the files with @format in order to avoid getting warnings afterwards.
  • Add tracking for the number of files with @format over time.

We finally got all those things wired up 1.5 weeks ago and the reception has been insane. Many people from various teams converted their codebase to prettier on their own. As of today, 15% of Facebook codebase has been converted over!

When I started working on prettier, I had a hunch that people were hungry for tools to solve formatting. But I had no idea that once the tooling was in place, people would rush to convert their codebase over! This is great confirmation that this project is useful to people and not just a gimmicky tool.

TypeScript Support Progress

@despairblue, @azz and @JamesHenry have been hard at work around getting TypeScript supported by prettier as it's the top requested feature. 2000 out of 11000 files in the TypeScript test suite are not yet properly printed. You can follow progress on #1480 and do not hesitate to help out!

Flow

Add trailing commas on flow generics (#1381)

The --trailing-comma=all option is supposed to add trailing commas everywhere possible, but as an oversight we forgot to do it for flow generics.

// Before
type Errors = Immutable.Map<
  Ahohohhohohohohohohohohohohooh,
  Fbt | Immutable.Map<ErrorIndex, Fbt>
>;

// After
type Errors = Immutable.Map<
Ahohohhohohohohohohohohohohooh,
Fbt | Immutable.Map<ErrorIndex, Fbt>,
>;

Inline nullable in flow generics (#1426)

The phase after printing things correctly is to tweak the output to make it closer to the way people write code in practice. Inlining optional flow types is a small thing that makes a difference.

// Before
type Cursor = Promise<
  ?{
    newCursor?: number,
    formatted: string,
  }
>;

// After
type Cursor = Promise<?{
newCursor?: number,
formatted: string,
}>;

Allow flow declarations to break on StringLiteralTypeAnnotations (#1437)

We can always find more places to add breaks when things don't fit 80 columns. This time it's around declaring a type as a constant string.

// Before
export type AdamPlacementValidationSingleErrorKey = 'SOME_FANCY_TARGETS.GLOBAL_TARGET';

// After
export type AdamPlacementValidationSingleErrorKey =
'SOME_FANCY_TARGETS.GLOBAL_TARGET';

Add space around = for flow generics default arguments (#1476)

Another example of small thing where we can improve the display of flow code. For function default arguments we put a space around = but didn't around flow generics.

// Before
class PolyDefault<T=string> {}

// After
class PolyDefault<T = string> {}

Don't break for unparenthesised single argument flow function (#1452)

I'm trying to figure out something to write here, but ... it just looks weird!

// Before
const selectorByPath:
  Path
 => SomethingSelector<
  SomethingUEditorContextType,
  SomethingUEditorContextType,
  SomethingBulkValue<string>
> = memoizeWithArgs(/* ... */)

// After
const selectorByPath: Path => SomethingSelector<
SomethingUEditorContextType,
SomethingUEditorContextType,
SomethingBulkValue<string>
> = memoizeWithArgs(/* ... */);

Fix optional flow parenthesis (#1357)

We were a bit too lenient around parenthesis for optional flow types. In one case in the entire Facebook codebase, it generated code with different semantics. As part of this fix, we hardened the list of types that can be written without parenthesis.

// Before
type X = ?(number, number) => number => void;

// After
type X = (?(number, number) => number) => void;

Skip trailing commas with FlowShorthandWithOneArg (#1364)

It is a parse error to add a trailing comma without parenthesis for arguments of arrow function types. We found one case in Facebook codebase when this happened, it's a very rare occurrence.

// Before
type IdeConnectionFactory =
  child_process$ChildProcess,
  => FlowIDEConnection = defaultIDEConnectionFactory;

// After
type IdeConnectionFactory =
child_process$ChildProcess,
=> FlowIDEConnection = defaultIDEConnectionFactory;

Reorder flow object props (#1451)

This one is an example where the way the AST is structured is not our favor. Instead of having a list of elements inside of a type, the AST is structured in a way where normal keys and array keys each have their own group. In order to restore the initial order, we're now reading from the original source :(

// Before
type Foo = {
  [key: string]: void,
  alpha: "hello",
  beta: 10
};

// After
type Foo = {
alpha: 'hello',
[key: string]: void,
beta: 10
}

Template Literal

Proper indentation for template literals (#1385)

A long standing issue with template literals and prettier is around the indentation of code inside of ${}. It used to be the indentation of the backtick but turned out to give poor results. Instead people tend to use the indent of the ${. We changed this behavior and it magically made GraphQL queries look pretty!

// Before
Relay.createContainer({
  nodes: ({ solution_type, time_frame }) => Relay.QL`
    fragment {
      __typename
      ${OptimalSolutionsSection.getFragment("node", {
    solution_type,
    time_frame
  })}
    }
  `
})
// After
Relay.createContainer({
  nodes: ({ solution_type, time_frame }) => Relay.QL`
    fragment {
      __typename
      ${OptimalSolutionsSection.getFragment("node", {
        solution_type,
        time_frame
      })}
    }
  `
})

Do not indent calls with a single template literal argument (#873)

Template literals are very hard to deal with for a pretty printer because the spaces inside are meaningful so you can't re-indent them. We didn't know what to do for a call with a single template literal so we didn't do anything, but we kept receiving reports of people saying that prettier indented it the wrong way, so we are now inlining them. Fingers crossed it is going to cover most use cases.

// Before
insertRule(
  `*, *:before, *:after {
    box-sizing: inherit;
  }`
);

// After
insertRule(</span>*, *:before, *:after {</span> <span class="pl-s"> box-sizing: inherit;</span> <span class="pl-s">}<span class="pl-pds">);

Fix windows line ending on template literals (#1439)

We manipulate line endings in a lot of places in prettier and took great care of handling both \n and \r\n except for template literals where we forgot. Now this is fixed!

// Before
const aLongString = `

Line 1

Line 2

Line 3

`;

// After
const aLongString = </span></span> <span class="pl-s">Line 1</span> <span class="pl-s">Line 2</span> <span class="pl-s">Line 3</span> <span class="pl-s"><span class="pl-pds">;

Inline template literals as arrow body (#1485)

We already inline template literals that are tagged (eg graphql`query`) but didn't for plain template literals. For the anecdote, it turns out the code was supposed to support it but it was using TemplateElement instead of TemplateLiteral :(

// Before
const inlineStore = preloadedState =>
  `
  <script>
    window.preloadedState = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
  </script>
`

// After
const inlineStore = preloadedState => </span></span> <span class="pl-s"> &lt;script&gt;</span> <span class="pl-s"> window.preloadedState = <span class="pl-s1"><span class="pl-pse">${</span><span class="pl-c1">JSON</span>.<span class="pl-en">stringify</span>(preloadedState).<span class="pl-c1">replace</span>(<span class="pl-sr"><span class="pl-pds">/</span>&lt;<span class="pl-pds">/</span>g</span>, <span class="pl-s"><span class="pl-pds">'</span><span class="pl-cce">\\</span>u003c<span class="pl-pds">'</span></span>)<span class="pl-pse">}</span></span></span> <span class="pl-s"> &lt;/script&gt;</span> <span class="pl-s"><span class="pl-pds">

Ternaries

Add parenthesis for unusual nested ternaries (#1386)

While working on printing nested ternaries, everyone focused on the ones with the shape of an if then else cond1 ? elem1_if : cond2 ? elem2_if : elem_else which is the most common. But, if you move move some ? and : around you can have another pattern. It looks almost the same but has a different meaning. In order to reduce confusion, we're adding parenthesis around the uncommon form.

// Before
cond1 ? cond2 ? elem2_if : elem2_else : elem1_else

// After
cond1 ? (cond2 ? elem2_if : elem2_else) : elem1_else

Only add parenthesis on ternaries inside of arrow functions if doesn't break (#1450)

There's an eslint rule no-confusing-arrows which suggests adding parenthesis for ternaries in arrow functions without brackets.

var x = a => 1 ? 2 : 3;
var x = a <= 1 ? 2 : 3;

It makes sense when code is in one line, but when it is split into multiple lines, the parenthesis are unnecessary given the indentation, so we now only put them when they serve their disambiguation purpose.

// Before
var x = a => (1 ? 2 : 3);
var x = a =>
  (1
    ? 2
    : 3);

// After
var x = a => (1 ? 2 : 3);
var x = a =>
1
? 2
: 3;

General JavaScript Improvements

Inline function declaration with single arg as object (#1173)

This one was often requested for React Stateless Functional Components (SFC). If you make use of a lot of them, it's likely going to be a big change for you.

// Before
const X = (
  props: {
    a: boolean,
  },
) => <div />;

// After
const X = (props: {
a: boolean,
}) => <div />;

Break inline object first in function arguments (#1453)

One thing we discovered early on is that people usually break the arguments of the function before breaking the return type. Unfortunately, the code responsible to inline single destructuring argument broke that assumption and it introduced bad looking code like this example. The good news is that it enables us to turn on inlining for single arguments that are typed with an object.

// Before
class X {
  async onDidInsertSuggestion({editor, triggerPosition, suggestion}): Promise<
    void
  > {
  }
}

// After
class X {
async onDidInsertSuggestion({
editor,
triggerPosition,
suggestion
}): Promise<void> {
}
}

Don't break on empty arrays and objects (#1440)

This one has been a long standing issue and is an easy fix, but was an invaluable tool: whenever someone reported that [] or {} would break, we were able to fix the example by fixing something else. So it was a great way to surface edge cases. Fortunately, this vein has now ran out and all the recent examples just look bad with no other reason than the fact that they are breaking. So it's time to finally do it!

// Before
const a = someVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeLong.Expression || [
];

// After
const a = someVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeLong.Expression || [];

Do not break on [0] (#1441)

We have a lot of issues where code breaks in array access when it doesn't look good. We don't yet have a good generic solution for it, but we can add a specific fix a common situation: [0].

// Before
queryThenMutateDOM(() => {
  title = SomeThing.call(root, "someLongStringThatPushesThisTextReall")[
    0
  ];
});

// After
queryThenMutateDOM(() => {
title = SomeThing.call(
root,
"someLongStringThatPushesThisTextReall",
)[0];
});

Indent do while condition (#1373)

We were not using the correct indentation logic for do-while condition but someone noticed, now we do!

// Before
do {}
while (someVeryLongStringA && someVeryLongStringB && someVeryLongStringC && someVeryLongStringD);

// After
do {}
while (
someVeryLongStringA &&
someVeryLongStringB &&
someVeryLongStringC &&
someVeryLongStringD
);

Preserve inline comment as last argument (#1390)

We forgot to add one case in the comment detection code when they appear last for JSX attributes and function arguments which made them go after the closing. In the case of JSX, it generated code that had a different meaning. Fortunately, since we don't usually commit commented out code it didn't affect production code, but it is not a good experience while coding.

// Before
const x = (
  <div
    attr1={1}>
//   attr3={3}
    {children}
  </div>
);

// After
const x = (
<div
attr1={1}
// attr3={3}
>
{children}
</div>
);

Break class expression returned by arrow call (#1464)

In 1.0, we made class be inline inside of arrow functions. It turns out that it doesn't work great when the class is non trivial, so we are reverting this change. We're trying really hard to avoid making trashy decisions like this where the style changes back and forth, but we allow ourselves to do it sometimes to fix mistakes!

// Before
export default (ViewComponent: Function, ContainerComponent: Function) => class
  extends React.Component {
  static propTypes = {};
};

// After
export default (ViewComponent: Function, ContainerComponent: Function) =>
class extends React.Component {
static propTypes = {};
};

Fix empty line in block with EmptyStatement (#1375)

This one was found by fuzzing. You're unlikely going to hit this in real code but it's good to know it is fixed!

// Input
if (a) {
  b;

;
}

// Before
if (a) {
b;

}

// After
if (a) {
b;

}

Commits

The new version differs by 48 commits0.

  • a81d5c1 1.3.0
  • 0785726 Inline template literals as arrow body (#1485)
  • f59aeef Break inline object first in function arguments (#1453) (#1173)
  • 8f9bb3a Break inline object first in function arguments (#1453)
  • 54b8cac Reorder flow object props (#1451)
  • c99a877 Do not break on [0] (#1441)
  • acfb14f Don't break on empty arrays and objects (#1440)
  • bafd724 Don't break for unparenthesised single argument flow function (#1452)
  • a335c26 Add space around = for flow generics default arguments (#1476)
  • 4b7d265 Fix windows line ending on template literals (#1439)
  • e392093 Only add parenthesis on ternaries inside of arrow functions if doesn't break (#1450)
  • 93cad97 Preserve inline comment as last argument (#1390)
  • 314e963 Add parenthesis for unusual nested ternaries (#1386)
  • 13f05fb Proper indentation for template literals (#1385)
  • c521406 [RFC] Do not indent calls with a single template literal argument (#873)

There are 48 commits in total.

See the full diff

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

Improve the default getJSON function

The default getJSON function simply saves the cq stats to a local file, just aside the original css as a .json.

However, webpack-dev-server is triggered even when the file didn't actually change.

To avoid triggering compilation in a loop, the default getJSON should be improved to be something like this:

getJSON: (cssFile, json) => {
                    const jsonData = JSON.stringify(json);
                    const jsonFilePath = `${cssFile}.json`;

                    const writeJson = () =>
                        fs.writeFile(jsonFilePath, jsonData, e => {
                            if (e) {
                                console.error(
                                    `Failed to save contaienr query json file: ${e}`
                                );
                            }
                        });

                    fs.readFile(jsonFilePath, 'utf8', (e, data) => {
                        // Write file if it doesn't exist yet, or if the contents changed
                        if (e || data !== jsonData) {
                            writeJson();
                        }
                    });
                },

Doesn't apply styles to newly injected container children

Assume a grid, with items popping in and out of existence, where grid is the container, and the items should have a specific with.
When the items are injected, styles are not applied automatically, since recalculation only happens on grid resize.

This is quite an annoyance with React, where components might be mounted / unmounted quite frequently.

A solution would be to pick up on such children using the mutation observer.

Support for nested @container queries

This would make the syntax a lot easier to read, where in a component's css file, instead of having all @container queries at the bottom, we could now have it right inside the affected selector.
(This would nicely complement BEM and suit-like naming conventions)

Like so:

.Button {
  @define-container
  // somestyles

  &__descendant {
    // somestyles
    
    @container (orientation: landscape) {
      // somestyles
    }
  }

  @container (width > 100px) {
    // some styles
  }
}

Once it gets processed to this:

.Button {
  @define-container
  // somestyles
}

.Button__descendant {
    // somestyles
}

@container (orientation: landscape) {
  .Button__descendant {
    // somestyles
  }
}

@container (width > 100px) {
  .Button {
    // some styles
  }
}

Everything would work as usual.

Make the postcss plugin usable in the browser

The v2 version relies on node's fs to save the container query stats as a JSON by default alongside the css file.

This in the browser is not needed, and makes it unnecessarily hard to bundle.

Probably make it an optional dependency instead.

Adopt a new (more css-friendly) syntax

Based on the discussion here: https://twitter.com/innovati/status/946155332719599622

The new proposed syntax (that'll be mostly adopted by eqcss too if everything goes well):

.Container {
  ...
}

@container .Container (width >= 320px) {
  .Element {
    ...
  }
}

(Whether the query's name will be @container or @element is not decided yet, so I'll support both for the time being.)

Where @container applies styles to elements inside the element, given by the selector.

The following should be possible too, although not BEM-like, and not encouraged by this particular project:

@container .some-selector .Container (width >= 320px) {
  .some-selector .Element {
    ...
  }
}

This makes the job of preprocessors slightly harder though, since it's a bit hard to decide where the boundary is between container-selector and element-selector.

Consider the following:

.wrapper {
    .Container {
        ...

        .another-selector {
            .Element {
                @container (width >= 320px) {
                    ...
                }
            }
        }
    }
}

With @media queries, a prerpocessor would lift the media query on the top level, wrapping everything else inside, which is however not the desired result for us:

// This is wrong!
@container (width >= 320px) {
    .wrapper .Container .another-selector .Element {
        ...
    }
}

Even if preprocessors do handle @container queries differently, they have no way of telling at which point the container selector begin and end.

Maybe the following is the closest to a solution:

.wrapper {
    .Container {
        ...

        @container (width >= 320px) {
            .another-selector {
                .Element {
                    
                }
            }
        }
    }
}

Here preprocessors can assume that everything outside a @container query is the container selector, and needs to be put in between the query keyword and the conditions, and anything inside would be element / child selectors.
Resulting in:

// This is correct!
@container .wrapper .Container (width >= 320px) {
  .another-selector .Element {
    ...
  }
}

Make the style-applying engine easily overridable

With v2.0, a new diffing algorithm calculates the styles that needs to be applied, and the props that need to be removed.
This allows the style applying engine to be easily replacable.
Using something like Styletron, for example instead of using Element.style.

Currently the change set looks as follows:

{
  addStyles: {
    border: "none",
  },
  removeProps: ["font-size"]
}

The only change needed though, is to separate styles generated by container units from regular ones, since the former changes a lot more. (On every single container size change.)
This means that you may want to treat those differently.

For example:
Styletron would create a great number of classes for all values generated by container units, like:

.a { font-size: 10px;}
.b { font-size: 10.123px;}
.c { font-size: 10.345px;}
.d { font-size: 10.567px;}
etc ...

Which basically means that for values, using styletron would not be a good solution, while using it to update normal styles would work very well.

Reconsider disabled properties on containers

As an attempt to avoid circulatory issues, refuse to parse the CSS if it's trying to change the container's width or height.

  • Either via a container unit in the same rule where the container was defined,
  • Or inside a @container query, whether the value's unit is container unit or not.

Also look into disabling other properties, like padding, which again could affect the container's size.

Limit the precision of container units

Currently, there's nothing limiting the precision, which results in very long floating numbers.

In most cases it's probably unnecessary, and is only a source of layout trashing.

Instead, the Container runtime could have a unitPrecision option (default = 2).

Question: is BEM required?

I generally hash my selectors in production and rely on CSS modules.

How does this repo fit into that environment?

Thanks..

Handle json files without "queries"

If the postcss plugin is not outputting anything (no containers were defined yet) the runtime should still work.

Currently, it gives an error instead:
image

Basically the runtime should work without a valid JSON, without throwing an error.

An in-range update of prettier is breaking the build 🚨

Version 1.4.0 of prettier just got published.

Branch Build failing 🚨
Dependency prettier
Current Version 1.3.1
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As prettier is β€œonly” a devDependency of this project it might not break production or downstream projects, but β€œonly” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this πŸ’ͺ

Status Details
  • ❌ continuous-integration/travis-ci/push The Travis CI build failed Details

Release Notes 1.4.0: TypeScript and CSS support

prettier-revolution-conf

TypeScript Support

This is the most requested feature for prettier. With 1.4.0, you can now use prettier to format your .ts and .tsx files!

The way prettier works is by using those project to generate an AST representation of the code and print it. Both babylon (the parser that powers babel) and flow are producing an AST approximately following the estree format for the JavaScript parts and then have special nodes for Flow-specific ones.

TypeScript, the same way as Flow, introduces special nodes for the syntax it introduces. Unfortunately, it doesn't follow the estree format for the rest of the JavaScript language. This puts us in a rough spot with prettier as we would have to essentially completely fork it in order to print TypeScript.

This incompatibility with the AST is not a new problem and another project struggled with it: ESLint. Because the AST is different, none of the ESLint rules are working. Fortunately for us, @JamesHenry and @soda0289 wrote a project called typescript-eslint-parser which takes a TypeScript AST and convert it to an estree one, just what we need for prettier!

After that project got setup inside of prettier, @azz, @despairblue and @Pajn implemented all the TypeScript-specific nodes and ensured that the 13k tests of the TypeScript test suite are correctly passing. This was a huge undertaking and it is finally ready to be used :)

We tested prettier on the biggest TypeScript projects we could find on GitHub to ensure that it prints correct code. We haven't spent a lot of time trying to optimize the way code is formatted yet, so if you see something strange, please raise an issue!

CSS, Less and SCSS Support

While TypeScript is the most requested feature from open source, CSS is the biggest one from Facebook engineers. Once you are used to pretty print your code in one language, you want to do it everywhere!

It turns out that CSS is a much smaller language than JavaScript and supporting it only took a few days. We are using postcss by @ai as the underlying parser which is able to parse CSS, Less and SCSS. We also depend on postcss-values-parser, postcss-selector-parser by @ben-eb postcss-media-query-parser by @dryoma.

Unfortunately, postcss right now doesn't parse Sass nor Stylus. We'd be happy to support them if someone is willing to do the work of printing them.

Note that prettier is currently just formatting the code, it does not respect any options yet such as singleQuote nor is doing any color or number normalization like we do for JavaScript.

Editor Integration

The first phase of the project was to make prettier output correct and good looking code. Now that it's in a good shape, we can spend time on making the integrations better. We just introduced support for two great features: maintain cursor position and being able to format a range instead of the entire file.

Note that we just landed the support inside of prettier itself, none of the editor integrations are using it yet. Also, we haven't really tried them out in practice so we're likely going to have to fix rough edges with them!

Add cursorOffset option for cursor translation (#1637) by @josephfrazier

Right now, we let editors figure out where the cursor should be, which they do an okay job at. But since we are printing the code, we can give the correct position!

Add --range-start/end options to format only parts of the input (#1609) by @josephfrazier

This one is a very often requested feature. Right now prettier only formats the entire file. Now it is possible to format a range.

The way it works is by going up through the AST in order to find the closest statement. This way you don't need to select exactly the right range that is valid. You can just drag in the rough place where the code you want to reformat it, and it's going to!

Adding filepath option in order to enable filetype inference (#1835) by @mitermayer

Since we are now formatting CSS and TypeScript, it is not convenient to have to specify the parser for every file. You can now pass the filepath of the file you are working on and prettier will read the extension and figure out the right parser to use.

Highlights

Wrap text content inside of JSX (#1120, #1671, #1827, #1829) by @karl

The biggest remaining issue that people have with prettier when printing JSX is when it is used when printing text. The behavior of prettier used to add an ugly {" "} before and if a line was too long, just leave it alone. Now we treat each word as a token and are able to make it flow correctly.

This is an awesome piece of work by @karl as not only did he implement the feature, but also introduced a new primitive inside of prettier in order to print a sequence of elements and break as soon as one hits the edge.

// Before
<div>
  Please state your
  {" "}
  <b>name</b>
  {" "}
  and
  {" "}
  <b>occupation</b>
  {" "}
  for the board of directors.
</div>

// After
<div>
Please state your <b>name</b> and <b>occupation</b> for the board of
directors.
</div>

Remove parenthesis for JSX inside of arrow functions (#1733) by @xixixao

People writing functional components are going to be happy about this one. We no longer put parens for arrow functions that return JSX.

// Before
const render1 = ({ styles }) => (
  <div style={styles}>
      Keep the wrapping parens. Put each key on its own line.
  </div>
);

// After
const render1 = ({ styles }) =>
<div style={styles}>
Keep the wrapping parens. Put each key on its own line.
</div>;

Improve template literal printing (#1664, #1714) by @josephfrazier

Template literal printing has always caused prettier a lot of difficulties. With 1.3.0 we massively improved the situation and with this release, I believe that we handle all the common situations in a good way.

In order to workaround issues, we added an utility that removes empty lines from the output, but it yielded some really weird results sometimes, this is now gone. Another tweak we've done is instead of indenting when ${ starts, we indent where the line that contains ${ starts.

Let us know if you still have issues with how template literals output after this release!

// Before
const Bar = styled.div`
  color: ${props => (props.highlight.length > 0 ? palette([
                 'text',
                 'dark',
                 'tertiary'
               ])(props) : palette([
                 'text',
                 'dark',
                 'primary'
               ])(props))} !important;
`

// After
const Bar = styled.div</span></span> <span class="pl-s"> color: <span class="pl-s1"><span class="pl-pse">${</span><span class="pl-smi">props</span> <span class="pl-k">=&gt;</span></span></span> <span class="pl-s"><span class="pl-s1"> <span class="pl-smi">props</span>.<span class="pl-smi">highlight</span>.<span class="pl-c1">length</span> <span class="pl-k">&gt;</span> <span class="pl-c1">0</span></span></span> <span class="pl-s"><span class="pl-s1"> <span class="pl-k">?</span> <span class="pl-en">palette</span>([<span class="pl-s"><span class="pl-pds">"</span>text<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>dark<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>tertiary<span class="pl-pds">"</span></span>])(props)</span></span> <span class="pl-s"><span class="pl-s1"> <span class="pl-k">:</span> <span class="pl-en">palette</span>([<span class="pl-s"><span class="pl-pds">"</span>text<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>dark<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>primary<span class="pl-pds">"</span></span>])(props)<span class="pl-pse">}</span></span> !important;</span> <span class="pl-s"><span class="pl-pds">

Use the same breaking rules for assignment and object values (#1721)

We have a lot of fine-tuned logic for how to break things after assignment (eg a = ...). We are now using the same one for object values. This should help for multi-line boolean logic, or big conditionals. This is also a good example of how we can create a consistent printer.

// Before
const o = {
  somethingThatsAReallyLongPropName: this.props.cardType ===
    AwesomizerCardEnum.SEEFIRST,
};

// After
const o = {
somethingThatsAReallyLongPropName:
this.props.cardType === AwesomizerCardEnum.SEEFIRST,
};

Indent conditions inside of !() (#1731)

There's been a steady stream of people complaining about the way it was rendered and was put on the list of things that are probably hard to do, will check later. It turned out to be super easy, so here you go!

// Before
const anyTestFailures = !(aggregatedResults.numFailedTests === 0 &&
  aggregatedResults.numRuntimeErrorTestSuites === 0);

// After
const anyTestFailures = !(
aggregatedResults.numFailedTests === 0 &&
aggregatedResults.numRuntimeErrorTestSuites === 0
);

Formatting Fixes

Put loop bodies on the same line when possible (#1498)

We were already doing this for if statements, we should be consistent and also do it for loops.

// Before
for (a in b)
  var c = {};

// After
for (a in b) var c = {};

Fix empty line with flow union (#1511) by @existentialism

We shouldn't indent things twice ;)

// Before
type Foo = Promise<
<span class="pl-k">|</span> { ok<span class="pl-k">:</span> <span class="pl-c1">true</span>, bar<span class="pl-k">:</span> string, baz<span class="pl-k">:</span> SomeOtherLongType }
<span class="pl-k">|</span> { ok<span class="pl-k">:</span> <span class="pl-c1">false</span>, bar<span class="pl-k">:</span> SomeOtherLongType }

>;

// After
type Foo = Promise<
{ ok: true, bar: string, baz: SomeOtherLongType } |
{ ok: false, bar: SomeOtherLongType }
>;

Do not put parens for single argument with end of line comment (#1518)

The detection code for whether an arrow function should be written without parenthesis just checked if there was a comment, but instead we only want comments that are inline like (/* comment */ num), not end of line comments.

// Before
KEYPAD_NUMBERS.map((num) => ( // Buttons 0-9
  <div />
));

KEYPAD_NUMBERS.map(num => ( // Buttons 0-9
<div />
));

Do not indent nested ternaries (#1822)

This avoids making it seems like it is indented by 4 characters instead of two. The downside is that if the condition is multi-line it's not going to be properly aligned, but I feel it's a better trade-offs. If you are doing nested ternaries, you usually have small conditions.

// Before
aaaaaaaaaaaaaaa
  ? bbbbbbbbbbbbbbbbbb
  : ccccccccccccccc
      ? ddddddddddddddd
      : eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg;

// After
aaaaaaaaaaaaaaa
? bbbbbbbbbbbbbbbbbb
: ccccccccccccccc
? ddddddddddddddd
: eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg;

Inline chained conditionals inside of jsx attribute (#1519)

We don't need to use the indentation to disambiguate another block as nothing can come after.

// Before
<div
  src={
    !isEnabled &&
      diffUpdateMessageInput != null &&
      this.state.isUpdateMessageEmpty
  }
/>;

// After
<div
src={
!isEnabled &&
diffUpdateMessageInput != null &&
this.state.isUpdateMessageEmpty
}
/>;

Unescape unnecessarily escaped characters in strings (#1575) by @josephfrazier

We are already trying to cleanup strings in various ways, this is another small addition that's going to remove \ that are not needed.

// Before
a = 'hol\a';

// After
a = 'hola';

Fix boolean for empty objects (#1590) by @dmitrika

We want to inline objects inside of a boolean expression as it looks weird to have { on its own line. But it turns out that it leads to weird behaviors for empty objects. So we keep them on their own line if they are empty.

const x = firstItemWithAVeryLongNameThatKeepsGoing ||
secondItemWithALongNameAsWell || {};

// After
const x =
firstItemWithAVeryLongNameThatKeepsGoing ||
secondItemWithALongNameAsWell ||
{};

Remove Parens from SequenceExpressions in ForStatements (#1597) by @k15a

It is common to assign multiple values inside of a for loop, now we don't add parenthesis anymore.

// Before
for ((i = 0), (len = arr.length); i < len; i++) {

// After
for (i = 0, len = arr.length; i < len; i++) {

Do not inline arrow when argument has a leading comment (#1660)

If you put block comments inside of arrow functions, we no longer mess everything up!

// Before
export const bem = block => /**
   * @param {String} [element] - the BEM Element within that block; if undefined, selects the block itself.
   */
element => /**
     * @param {?String} [modifier] - the BEM Modifier for the Block or Element; if undefined, selects the Block or Element unmodified.
     */
modifier =>

// After
export const bem = block =>
/
* @param {String} [element] - the BEM Element within that block; if undefined, selects the block itself.
*/
element =>
/

* @param {?String} [modifier] - the BEM Modifier for the Block or Element; if undefined, selects the Block or Element unmodified.
*/
modifier =>

Fix last comments of imports (#1677)

Another place where we have to do special logic for comments!

// Before
import {
  ExecutionResult,
  DocumentNode,
  /* tslint:disable */
  SelectionSetNode,
} /* tslint:enable */ from 'graphql';

// After
import {
DocumentNode,
/* tslint:disable /
SelectionSetNode,
/
tslint:enable */
} from 'graphql';

Handle comments in member chain (#1686, #1691)

We handled some placements before and kept adding places where they could appear, now we switch to a more general approach. Hopefully those issues shouldn't crop up in the future anymore.

// Before
const configModel = this.baseConfigurationService.getCache().consolidated // global/default values (do NOT modify)
  .merge(this.cachedWorkspaceConfig);

// After
const configModel = this.baseConfigurationService
.getCache()
.consolidated // global/default values (do NOT modify)
.merge(this.cachedWorkspaceConfig);

Use expandLast for nested arrow functions (#1720)

// Before
f(action => next =>
    next(action));

// After
f(action => next =>
next(action),
);

Put JSX comments inside of the parenthesis (#1712)

This mostly affects Facebook engineers where we automatically add $FlowFixMe when pushing a new version of flow. Now it no longer messes up those comments.

// Before
const aDiv = /* $FlowFixMe */
(
  <div className="foo">
    Foo bar
  </div>
);

// After
const aDiv = (
/* $FlowFixMe */
<div className="foo">
Foo bar
</div>
);

Force \n for multiple variable declarations (#1723)

This one has been very often requested. We used to only break multiple variable declarations if the line was > 80 columns. Now we do it regardless if there's at least one with an assignment.

// Before
var numberValue1 = 1, numberValue2 = 2;

// After
var numberValue1 = 1,
numberValue2 = 2;

Inline | null and | void (#1734)

The expanded version of flow union looks good when they are many objects but if it's used for nullability, the it looks very weird. We're now inlining | null and | void.

// Before
interface RelayProps {
  articles:
    | Array<
      | {
        __id: string,
      }
      | null
    >
    | null
}

// After
interface RelayProps {
articles: Array<{
__id: string,
} | null> | null,
}

Break on implements instead of extends (#1730)

We no longer break on extends. This should make classes with extends that can break look less wonky.

// Before
class MyContractSelectionWidget
  extends React.Component<
    void,
    MyContractSelectionWidgetPropsType,
    void
  > {
  method() {}
}

// After
class MyContractSelectionWidget extends React.Component<
void,
MyContractSelectionWidgetPropsType,
void
> {
method() {}
}

Inline single import (#1729)

The same way we don't break long require calls, we no longer break import statements if there is only a single thing being imported.

// Before
import somethingSuperLongsomethingSuperLong
  from "somethingSuperLongsomethingSuperLongsomethingSuperLong";

// After
import somethingSuperLongsomethingSuperLong from "somethingSuperLongsomethingSuperLongsomethingSuperLong";

Add the ability for SequenceExpression to break (#1749)

Did you know that if none of your code were statements, you could use () instead of {} and , instead of ;? Now you do. Some people exploit this fact when returning things from arrow functions. This is not recommended but it's easy to support in prettier so might as well Β―_(ツ)_/Β―

// Before
const f = (argument1, argument2, argument3) =>
  (doSomethingWithArgument(argument1), doSomethingWithArgument(
    argument2
  ), argument1);

// After
const f = (argument1, argument2, argument3) => (
doSomethingWithArgument(argument1),
doSomethingWithArgument(argument2),
argument1
);

Don't force line break in empty loop bodies (#1815)

Loops with empty body no longer have their {} split into two lines.

// Before
while (true) {
}

// After
while (true) {}

Preserve empty lines between switch cases with comments (#1708)

// Before
switch (true) {
  case true:
  // Good luck getting here
  case false:
}

// After
switch (true) {
case true:

// Good luck getting here
case false:
}

Correctness

Remove ast-types (#1743, #1744, #1745, #1746, #1747)

We used to find where to put comments by traversing the AST using the definition from ast-types. This occasionally caused issues when some field wasn't declared, we wouldn't find the node and either print comments in an incorrect location or throw an error. It turns out that we don't need to keep this mapping and can just traverse the objects and if a node has a type field, then it's a node.

// Before
Error: did not recognize object of type "ObjectTypeSpreadProperty"

// After
type X = {...Y//};
type X = {/
/...Y};

Preserve unusual unicode whitespace (#1658, #1165) by @karl and @yamafaktory

If you were adding invisible characters inside of JSX text, we would replace them by regular spaces. I don't know why anyone would ever want to do that, but now we print it back as is!

Don't let trailing template literal comments escape (#1580, #1713, #1598, #1713) by @josephfrazier and @k15a

We used to have some pretty complicated (and not working well) code to handle comments inside of template literals. We introduced a really nice solution for JSX {} expressions. The idea is to introduce a boundary before the end of the } and if we still have unprinted comments, then flush them all at once, put a \n and print the }. We are now using this logic for template literals :)

// Before
`${0} // comment`;

// After
</span><span class="pl-s1"><span class="pl-pse">${</span></span></span> <span class="pl-s"><span class="pl-s1"><span class="pl-c1">0</span></span></span> <span class="pl-s"><span class="pl-s1"><span class="pl-c"><span class="pl-c">//</span> comment</span></span></span> <span class="pl-s"><span class="pl-s1"><span class="pl-pse">}</span></span><span class="pl-pds">;

Parenthesize await correctly (#1513, #1595, #1593) by @bakkot and @existentialism

We don't have an automated way to put parenthesis, we instead specify all the possible combinations of nodes and when they should or shouldn't have parenthesis. So there's likely a long tail of unusual combinations that are still remaining. In this case, we made await handling a lot more robust by both adding parenthesis where they are needed and removing them when they are not.

// Before
(await spellcheck) && spellcheck.setChecking(false);
new A((await x));

// After
await (spellcheck && spellcheck.setChecking(false));
new A(await x);

Preserve getter/setter info on flow ObjectTypeProperty (#1585) by @josephfrazier

Another long tail option that we haven't got right!

// Before
type T = { method: () => void };

// After
type T = { get method(): void }

Add parenthesis for single arg types with generics (#1814)

Another case of sneaky parenthesis that we didn't properly add!

// Before
type ExtractType = <A>B<C> => D

// After
type ExtractType = <A>(B<C>) => D

Fall back to non-strict mode in babylon (#1587, #1608) by @josephfrazier

We want prettier to be able to parse all the JavaScript out there. For babylon parser, we have to chose whether a file is using strict mode or not. We opted in to use strict mode by default as most files parse that way. But if you have octal literals like 0775, it would not even parse. Now if it fails to parse in strict mode, we're going to try again in non-strict. We also allow return outside of a function as it's valid in node files.

// Before
SyntaxError

// After
return 0775;

CLI

Allow --write to be used with --list-different (#1633)

This is useful to combine the two if you are writing a commit hook to tell the user what actually changed in a single command.

Ignore node_modules when running prettier from CLI (#1683) by @thymikee

It's very easy to run prettier over the node_modules/ folder by mistake which is something you almost never want to. So now we disable it by default and add a --with-node-modules option if you really want to.

Traverse dot files for glob (#1844) by @jhgg

We enabled the option to go through .dotfiles in the glob parsing library we are using. This means that writing * will now catch .eslintrc.

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

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.