Giter Site home page Giter Site logo

wmertens / styled-vanilla-extract Goto Github PK

View Code? Open in Web Editor NEW
116.0 4.0 9.0 1.1 MB

A 0-runtime styled-components-like API for Qwik using vanilla-extract.

License: MIT License

JavaScript 6.64% TypeScript 93.36%
hacktoberfest css-in-js qwik styled-components vanilla-extract

styled-vanilla-extract's Introduction

Styled Vanilla-Extract βš‘οΈπŸ’…

This provides a Styled-Components-like (SC) API for Qwik, using vanilla-extract (VE) and stylis. This combination yields a type-checked 0-runtime CSS-in-TS project.

Try it out now on πŸ‘‰ StackBlitz πŸ‘ˆ.

Example:

  • styles.css.ts:

    import {styled} from 'styled-vanilla-extract/qwik'
    
    export const RedText = styled.span`
      color: red;
    `

gets converted at build time to

  • styles.css.ts.vanilla.css:

    .werasf1 {
      color: red;
    }
  • styles.css.ts.vanilla.js:

    import './styles.css.ts.vanilla.css'
    import {styled as _spofw} from 'styled-vanilla-extract/qwik-styled'
    
    export var RedText = _spofw('span', 'werasf1')

RedText is a Qwik Lite component ready for use, and the CSS will be included by Qwik automatically.

Type-checking happens automatically thanks to the fact that the source file is a .ts file (you can use plain js too) and all helpers have proper typing.

Installation

Automatically

Run npx @builder.io/qwik add styled-vanilla-extract.

Manually

Install the needed NPM modules; they can be dev dependencies because Qwik will bundle them correctly for client and server.

npm i -D styled-vanilla-extract @vanilla-extract/css

Then, add the Vite plugin to your vite.config.ts, for example:

import {defineConfig} from 'vite'
import {qwikVite} from '@builder.io/qwik/optimizer'
import {qwikCity} from '@builder.io/qwik-city/vite'
import tsconfigPaths from 'vite-tsconfig-paths'
// ---------------- ADD THIS ----------------
import {vanillaExtractPlugin} from 'styled-vanilla-extract/vite'

export default defineConfig(() => {
  const cfg = {
    build: {sourcemap: true},
    plugins: [
      qwikCity(),
      qwikVite(),
      tsconfigPaths(),
      // ---------------- ADD THIS ----------------
      // This has to come somewhere after qwikVite, or the exports break
      vanillaExtractPlugin(),
    ],
  }
  return cfg
})

Then, check if your editor has styled-components support. For example, VS Code has vscode-styled-components.

Usage

This library is complementary to vanilla-extract, so head over to the vanilla-extract docs to learn the basics.

styled

You use styled to create Qwik components that you can import. This uses the same configuration objects as the vanilla-extract style() function:

header.css.ts:

import {style, styled} from 'styled-vanilla-extract/qwik'

// Local classname that makes things fancy
export const fancy = style({})

// Header: a Qwik Lite Component
export const Header = styled.header({
  padding: '0.5em',
  border: 'thin solid var(--color-hint)',
  borderBottom: 'none',
  selectors: {
    [`${fancy} &, ${fancy}&`]: {
      background: 'gold',
    },
  },
})

header.tsx:

import {Header, fancy} from './header.css'

export default component$(() => {
  // do header stuff
  return (
    <Header class={isFancy && fancy}>
      Header, possibly fancy.
      <br />
      The classname it uses is {Header.class}.
    </Header>
  )
})

css

There's also css template string helper to convert CSS syntax to vanilla-extract syntax. You can use it anywhere that accepts vanilla-extract style objects:

header.css.ts:

import {style, styled, css} from 'styled-vanilla-extract/qwik'

// Local classname
export const fancy = style({})

// Header: a Qwik Lite Component
export const Header = styled.h1(css`
  padding: 0.5em;
  border: thin solid var(--color-hint);
  border-bottom: none;
  ${fancy} &, ${fancy}&: {
    background: gold;
  }
`)

combined

Both style and styled can be used as tagged template functions, so the above can also be written as

header.css.ts:

import {style, styled} from 'styled-vanilla-extract/qwik'

export const Fancy = style``

// Header: a Qwik Lite Component
export const Header = styled.h1`
  padding: 0.5em;
  border: thin solid var(--color-hint);
  border-bottom: none;
  ${fancy} &, ${fancy}&: {
    background: gold;
  }
`

Only emitting styles you use

By default, the CSS you create will be emitted in a .css file that your html will load.

You can instead get the CSS as a string that you then give to Qwik's useStyles$(). To do this, you must have a default export in your definition:

header.css.ts:

import {styled} from 'styled-vanilla-extract/qwik'

// This will be replaced with the CSS
export default ''

// Header: a Qwik Lite Component
export const Header = styled.h1`
  padding: 0.5em;
  border: thin solid var(--color-hint);
  border-bottom: none;
`

Header.tsx:

import {component$, useStyles$} from '@builder.io/qwik'
import style, {Header} from './header.css'

export default component$(() => {
  useStyles$(style)

  return <Header>I'm styled!</Header>
})

This has the advantage that your initial HTML includes only the styles you actually use, and they are inline, which reduces lag. If you are building a Single Page Application, this is most likely what you want.

Notes

  • All styles you create in a css.ts file are included in the CSS output. They do not get tree-shaken, unlike the exported identifiers. This is vanilla-extract behavior.
  • Qwik doesn't do hot reloading at the moment. It also has problems with changing .css files. You might have to reload the page manually sometimes to get styles to apply.

Migrating from Styled Components

Several features are not supported because they are impossible as 0-runtime, or don't make sense in Qwik.

Replacing function interpolation

Instead of embedding a function in your CSS like `color: ${p => p.error ? 'red':'black'}`, you should use extra classes, inline styles, CSS variables, or a combination thereof. Any option is easy to implement with Qwik.

import {Text, showError} from './component.css'

// ... hasError is a boolean
// Object of classnames and booleans
<Text class={{[showError]: hasError}}>text</Text>
// Class string
<Text class={hasError && showError}>text</Text>
// Style object
<Text style={{color: hasError ? 'red' : 'black'}}>text</Text>
// CSS variable that you use in your CSS
<Text style={{"--color-hint": hasError ? 'red' : 'black'}}>text</Text>

Replacing themes

Use CSS variables instead. They are supported in all relevant browsers.

You can also import any code you like to create the CSS at build time, there are no restrictions, go wild!

Vanilla-extract also has nice helper projects for this purpose, Sprinkles and Recipes.

Extending a component

A QwikStyledComponent can be passed to style and styled to Instead of using an existing component to build on, compose the styles that vanilla-extract generates:

import {styled, css} from 'styled-vanilla-extract'

const Button = styled.button`
  text-size: 3em;
`

export const RedButton = styled.button([
  Button,
  css`
    background-color: red;
  `,
])

Use as another tag, extending another component, adding props

Things like const Foo = styled(Bar).as('ul').props(...) make the API more complex and are not (yet) supported.

This library aims to stay lean, but if DX can be improved new features will be considered.

styled-vanilla-extract's People

Contributors

caass avatar dmitry-stepanenko avatar franck-co avatar n8sabes avatar theayes avatar wmertens 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

styled-vanilla-extract's Issues

Autocomplete Not Working

Installing styled-vanilla-extract into a fresh project with yarn qwik add styled-vanilla-extract installs the plugin correctly but the autocomplete is not working as intended. I tested this on the latest versions of qwik and styled-ve. I also checked on the stackblitz that is provided in the README, which also has the same issue.

  • Qwik: 0.16.1
  • styled-vanilla-extract: 0.5.3

I apologize if this is mentioned anywhere but I couldn't find anywhere mentioning that autocomplete is not supported by this library (since @vanilla-extract/css supports it). Let me know if you need more information.

Styled compoents way doesn't seem to work correctly.

Yesterday I've setup some templates which all worked fine a fresh qwik project. Now I'm trying it again and it doesn't seem to be correctly set up as the component get's literally inserted into html.
image
If I do the vanilla-extract way of inserting the object into the class field it works normally however.

This is the code:
image

Styled Vanilla Extract crashes in Qwik Nx projects

Describe the bug
styled-vanilla-extract, as defined in the Qwik Documentation crashes server-side.

To Reproduce

Below is a 2~3 minute configuration that demonstrates styled-vanilla-extract generating a [vite] Internal sever error. I've also included two lines of code for non-styled support from @vanilla-extract as a working reference.

1. Create a clean workspace

pnpx create-nx-workspace@latest foobar --preset=ts
cd foobar
pnpm add -D qwik-nx
pnpm exec nx g qwik-nx:app qwik --no-interactive

2. Since qwik add styled-vanilla-extract is broken in Qwik Nx, install VE and SVE manually β€”

pnpm add -D @vanilla-extract/vite-plugin styled-vanilla-extract @builder.io/qwik @vanilla-extract/css undici --filter qwik

3. Update / Add these 3 files

code .

// vite.config.ts

/// <reference types="vitest" />
import { qwikVite } from '@builder.io/qwik/optimizer';
import { qwikCity } from '@builder.io/qwik-city/vite';
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
// import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; // WORKS
import { vanillaExtractPlugin } from "styled-vanilla-extract/vite";     // DOES NOT WORK

export default defineConfig({
  plugins: [
    qwikCity(),
    qwikVite({
      client: {
        outDir: '../../dist/packages/qwiklab/client',
      },
      ssr: {
        outDir: '../../dist/packages/qwiklab/server',
      },
    }),
    tsconfigPaths(),
    vanillaExtractPlugin(),
  ],
  preview: {
    headers: {
      'Cache-Control': 'public, max-age=600',
    },
  }
});
// routes/index.tsx

import { component$ } from '@builder.io/qwik';
import type { DocumentHead } from '@builder.io/qwik-city';
import { RedText } from './styles.css';

export default component$(() => {
  return (
    <RedText>
      Qwik Styled Component -- Red Text!
    </RedText>
  );
});

export const head: DocumentHead = {
  title: 'Welcome to Qwik',
  meta: [
    {
      name: 'description',
      content: 'Qwik site description',
    },
  ],
};
// routes/styles.css.ts

import {styled} from 'styled-vanilla-extract/qwik'

export const RedText = styled.span`
  color: red;
`

4. Run

nx serve qwik

Expected behavior
It should work, but crashes with a server-side error:

[vite] Internal server error: Failed to load url /*PROJ_PATH*/foobar/packages/qwiklab/~~~/foobar/src/routes/styles.css.ts (resolved id: /*PROJ_PATH*/foobar/packages/qwiklab/~~~/foobar/src/routes/styles.css.ts). Does the file exist?

NOTE Reconfigure the vite.config.ts to use the standard Vanilla Extract vite plugin and it works fine. @wmertens, any ideas why?

Additional context

https://qwik.builder.io/integrations/integration/styled-vanilla-extract/
https://github.com/wmertens/styled-vanilla-extract
https://vanilla-extract.style/documentation/integrations/vite/
https://vanilla-extract.style/documentation/getting-started/#create-a-style

Add any other context about the problem here.

See Related Issue: Styled Vanilla Extract crashes in Qwik Nx projects

css autocompletion

hello i cant find anywhere in the issues if its something you guys are gonna work on this or not so as an idea to get correct types i found csstype package im currently using that should not cause problem i guess

image

variants not working when there's an extra dot in file name.

Describe the bug

i created a file, named button.component.css.ts then created a styled component:

export const buttonVariants = {
  solid: style({}),
  outlined: style({}),
};


export const StyledButton = styled.button`
  background-color: yellow;
  color: black;

  &${buttonVariants.outlined} {
    border-width: 2px;
    border-color: red;
    border-style: solid;
  }
`;

the normal styles are working fine, but the styles applied to variant is not working.
when i rename file to component.css.ts, the variants are also working.

System Info

System:
    OS: Linux 6.1 Arch Linux
    CPU: (12) x64 Intel(R) Core(TM) i7-9850H CPU @ 2.60GHz
    Memory: 8.37 GB / 15.26 GB
    Container: Yes
    Shell: 3.6.0 - /bin/fish
  Binaries:
    Node: 19.7.0 - ~/.local/share/pnpm/node
    Yarn: 1.22.19 - /usr/bin/yarn
    npm: 9.5.0 - ~/.local/share/pnpm/npm
  Browsers:
    Chromium: 110.0.5481.100
    Firefox: 110.0
  npmPackages:
    @vanilla-extract/css: ^1.9.5 => 1.9.5 
    vite: 4.1.4 => 4.1.4

Used Package Manager

pnpm

Logs

No response

Validations

How to use styled-vanilla-extract in a qwik package?

I tried to create an UI package with your styled-vanilla-extract. For that I kickoff the Qwik "component library" starter project. But when I use it in a qwik application the css is not working and the css is not loaded.
The styling is working when I put my styled-vanilla-extract component inside the qwik application directly.
Do you have a clue how to fix?

Bildschirmfoto 2023-08-11 um 15 13 37

Bun Installation not working?

I've installed styled-vanilla-extract through bun and it appears to be me missing "stylis"

[ERROR]
Build failed with 1 error:
../../node_modules/styled-vanilla-extract/lib/css.qwik.mjs:2:24: ERROR: Could not resolve "./node_modules/stylis/src/Parser.qwik.mjs"
[STACKTRACE]
    at failureErrorWithLog (/home/ayes/WebstormProjects/Calendarium/node_modules/@vanilla-extract/integration/node_modules/esbuild/lib/main.js:1636:15)
    at /home/ayes/WebstormProjects/Calendarium/node_modules/@vanilla-extract/integration/node_modules/esbuild/lib/main.js:1048:25
    at runOnEndCallbacks (/home/ayes/WebstormProjects/Calendarium/node_modules/@vanilla-extract/integration/node_modules/esbuild/lib/main.js:1471:45)
    at buildResponseToResult (/home/ayes/WebstormProjects/Calendarium/node_modules/@vanilla-extract/integration/node_modules/esbuild/lib/main.js:1046:7)
    at /home/ayes/WebstormProjects/Calendarium/node_modules/@vanilla-extract/integration/node_modules/esbuild/lib/main.js:1075:16
    at responseCallbacks.<computed> (/home/ayes/WebstormProjects/Calendarium/node_modules/@vanilla-extract/integration/node_modules/esbuild/lib/main.js:697:9)
    at handleIncomingPacket (/home/ayes/WebstormProjects/Calendarium/node_modules/@vanilla-extract/integration/node_modules/esbuild/lib/main.js:752:9)
    at Socket.readFromStdout (/home/ayes/WebstormProjects/Calendarium/node_modules/@vanilla-extract/integration/node_modules/esbuild/lib/main.js:673:7)
    at Socket.emit (node:events:514:28)
    at addChunk (node:internal/streams/readable:376:12)
    at readableAddChunk (node:internal/streams/readable:349:9)
    at Readable.push (node:internal/streams/readable:286:10)
    at Pipe.onStreamRead (node:internal/stream_base_commons:190:23

I also already tried reinstalling all dependencies. The Project is the normal Qwik Demo project without any other changes made. The only other thing would be that it is installed in a workspace monorepo.

Get "QWIK WARN Duplicate implementations of "JSXNode" found" when using `styled` function.

Describe the bug

Using components created by styled function in styled-vanilla-extract/qwik causing warning QWIK WARN Duplicate implementations of "JSXNode" found when start the server using vite --open --mode ssr.

Reproduce the bug

Using pnpm create qwik@latest to create a minimal qwik app. Then create file index.css.ts under src/routes folder. Using the code given in the documentation:

import { styled } from 'styled-vanilla-extract/qwik'

export const BlueBox = styled.div`
  display: block;
  width: 100%;
  height: 500px;
  background: blue;
`;

and modify the src/routes/index.tsx to

import { component$ } from "@builder.io/qwik";
import type { DocumentHead } from "@builder.io/qwik-city";
import { BlueBox } from './index.css';

export default component$(() => {
  return (
    <>
      <h1>Hi πŸ‘‹</h1>
      <p>
        Can't wait to see what you build with qwik!
        <br />](
        Happy coding.
      </p>
      <Cmp></Cmp>
    </>
  );
});

export const Cmp = component$(() => {
  return <BlueBox />;
});

export const head: DocumentHead = {
  title: "Welcome to Qwik",
  meta: [
    {
      name: "description",
      content: "Qwik site description",
    },
  ],
};

(This still follows the Qwik official documentation)

Then start the server by running npm run start (or equivalently vite --open --mode ssr)

Then the QWIK WARN Duplicate implementations of "JSXNode" found will be logged into console.

This warning will exist as long as the src/routes/index.tsx uses <Bluebox />

This warning is quite annoying, and I don't know what this warning indicates on my apps (and the possible consequences of it). I don't if this is bug originate from this library or the Styled-components it depends on. For now, I will just use only style function.

Contribution, Local Development, and Debugging

@wmertens, In the interest of contributing to styled-vanilla-extract, it would be useful to have a more clear contribution section on how to build locally and import into a local Qwik project. Maybe this is easy and it’s just my own knowledge gap.

After cloning the repo and running the build script, I then tried to install a link to the root, libs, or qwik directory in a Qwik test project, but cannot get it to work. What is the correct way to do this? Or, how to debug with the integrated test environment (to debug the vite plugin).

Last night I had some time debug the vite plugin issue # 7 for a potential PR.

HMR not working

Live edits to styled components are not being rendered by HMR. You must to stop and restart dev mode between edits which is quite inefficient.

It has not worked for some time. I am using the main branch.

    "@builder.io/qwik": "github:builderio/qwik-build",
    "@builder.io/qwik-city": "github:builderio/qwik-city-build",

Dynamic variable syntax consistency

QUESTION: In the interest of consistency and ease of use, shouldn't the syntax below in RedText work the same as a VE attribute values? Or is my syntax below in RedText malformed?

// styles.css.ts
import { keyframes, style, createVar } from '@vanilla-extract/css';
import { styled } from 'qwik-styled-ve'

export const colorVar = createVar();
export const widthVar = createVar();

// qwik-styled-ve
export const RedText = styled.span`
  color: ${colorVar};
`

// vanilla-extract
export const container = style({
  border: `dashed ${widthVar} ${colorVar}`,
});

export default "CSS"

`styled` doesn't show types for style objects

type StyledParam =
| StyleRule
| (StyleRule | QwikStyledComponent | ClassNames)[]
| TemplateStringsArray

If you had this:

export const GreenButton = styled.button({
  backgroundColor: "green",
  color: "white"
})

…you should get autocompletion for CSS properties, but it doesn't show anything.

Also, StyleRule could be ComplexStyleRule to allow for style objects that include selectors.

CleanShot 2023-08-10 at 6 00 26@2x

Template literals & interpolation

I would expect this to work, but for some reason it doesn't. I suppose it has something to do with how it is converted to object notation, but couldn't quite put my finger on it.

const mqs = Object.values(mq)
  .map((v) => `@media ${v} { color: red; }`)
  .join(" ")

// outputs: @media (width >= 768px) { color: red; } @media (width >= 1280px) { color: red; }

const fails = style`
    color: blue;
    ${mqs}
`
const alsoFails = style`
    color: blue;
    ${Object.values(mq).map((v) => `@media ${v} { color: red; }`).join(" ")}
`

const andAlsoFails = style`
    color: blue;
    ${"@media (width >= 768px) { color: red; } @media (width >= 1280px) { color: red; }"}
`

However, this works just fine:

const works = style`
    color: blue;
    @media (width >= 768px) { color: red; } @media (width >= 1280px) { color: red; }
`

Is this a limitation or am I doing something wrong here?

vanillaExtractPlugin not working in vite.config.ts

WORKS (but not HMR)
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';

DOES NOT WORK AT ALL (as defined in the docs)
import { vanillaExtractPlugin } from 'styled-vanilla-extract/vite';

Not sure when it broke, but I am using the main branch.

    "@builder.io/qwik": "github:builderio/qwik-build",
    "@builder.io/qwik-city": "github:builderio/qwik-city-build",

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.