tw-in-js / typescript-plugin

TypeScript language service plugin that adds IntelliSense for tailwindjs
MIT License
41 stars 6 forks source link

With plugins, auto-completion requires manual TypeScript typings in Twind configuration (error highlighting and hover information work fine out of the box) #8

Open danielweck opened 3 years ago

danielweck commented 3 years ago

For example, there is no auto-completion for form-input from @twind/forms, or lg:prose-xl from @twind/typography. Thank you :)

sastan commented 3 years ago

I know. I'm currently working on re-writing the plugin to support custom auto-completion for plugins. The plugins you mentioned will be updated to support this. It will look something like this for custom plugins:

import type { ThemeSection, FromTheme } from 'twind'

declare module 'twind' {
  interface Theme {
    scrollSnap: ThemeSection
  }

  interface Variants {
    ltr: string
  }

  interface Plugins {
    'scroll-snap': 'none' | 'x' | 'y' | FromTheme<'scrollSnap'>
  }
}

I update this issue once I have updated this plugin.

sastan commented 3 years ago

This should now work. I will update the plugins in the next days.

danielweck commented 3 years ago

The latest update warns about unknown tokens by highlighting keywords with a squiggly orange underline. That's great, thank you! :)

Taking the "@twind/forms" plugin as an example, is there anything we should configure in order to register the additional tokens, or does this happen automatically? (no rush to implement this if not done already, just wondering ;)

Screenshot 2021-03-16 at 06 59 58
sastan commented 3 years ago

Until I have updated the plugin or someone provides a PR... You can try this:

declare module 'twind' {
  interface Plugins {
    'form-input': ''
  }
}

Take a look at the defintions for the core plugins: https://github.com/tw-in-js/twind/blob/main/src/types/completion.ts#L128

danielweck commented 3 years ago

You can try this:

declare module 'twind' {
  interface Plugins {
    'form-input': ''
  }
}

Mhmm, I have tried different techniques, to no avail :(

/// <reference path='../twind.d.ts'/>
import '../twind.d.ts';

tsconfig.json

    "files": [
      "./twind.d.ts"
    ]
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line unused-imports/no-unused-imports
import type { Plugins as _P } from '../twind.d.ts';

Have you successfully managed to augment the Plugins interface?

sastan commented 3 years ago

Have you successfully managed to augment the Plugins interface?

Yes. Sorry for the lack of documentation.

Create a twind.config.{ts,js,cjs,mjs} in your root folder. I will add support for custom file soon. This config is evaluated and the plugins, variants, theme, and dark mode are read from there.

import { forms, formInput } from '@twind/forms'

/** @type {import('twind').Configuration} */
export default {
  plugins: { forms, 'form-input':  formInput}
}

Downside: Currently only the simple name can be inferred – meaning no params: form-input-lg (if there was such thing). To support that as well we augment the Plugins interface:

This can be done in any file that is included in the typescript compilation. Lets put into the config:

import { forms, formInput } from '@twind/forms'

/** @type {import('twind').Configuration} */
export default {
  plugins: { forms, 'form-input':  formInput}
}

declare module 'twind' {
  interface Plugins {
    // forms should have been detected from setup – not need to add it
    // forms: ''

    // We want to add sm and lg modifiers to the form-input
    'form-input':
      | ''    // plain form-input
      | 'sm' // form-input-sm
      | 'lg' // form-input-lg
  }
}

Downside: A lot of extra types. mapleLeaf and I are thinking of creating a plugin API that would allow detecting all possible class names from the plugin directly. No need for types.

PS You should use the twind.config.ts in you sources as well.

import { setup } from 'twind'
import config from '../twind.config`

setup(config)

The issue I just now realized is that autocompletion and diagnostic/hover use different ways.

Maybe I need to adjust the autocompletion part to invoke tw as well. What do you think?

danielweck commented 3 years ago

Brilliant, this works :)

(I am using the typography plugin as well, and the prose syntax is supported out of the box from the plugin definition)

Just a note specific to Preact WMR: the public subfolder has a special significance, such that the twind.config.ts (or .js) must be located inside it (otherwise the server will fail to fetch from the "external" parent folder, even with an alias directive).

No big deal though, I just added twind.config.ts at the project root with:

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
export { default } from './public/twind.config.ts';

By the way, I love that the config file can be TypeScript instead of Javascript! 👍

danielweck commented 3 years ago

Maybe I need to adjust the autocompletion part to invoke tw as well. What do you think?

Yes I can see how that could help.

For example right now with the typography plugin:

declare module 'twind' {
    interface Plugins {
        prose: '' | 'xl';
    }
}

...both the grouped and non-grouped syntax work fine with autocompletion, error squiggly underline, and hover info (i.e. raw CSS preview):

tw`prose prose-xl lg:prose-xl`

tw`prose(& xl lg:xl)`;

...however if I use lg instead of xl, autocompletion fails (because I didn't explicitly declare it in the Twind type config) but hover and compiler checks work fine. This inconsistency is confusing indeed, but this will ultimately be fixed when the types don't have to be explicitly listed in the Twind config, right?

sastan commented 3 years ago

Just a note specific to Preact WMR

I'm aware of this. That's why the default config lookup will [src/,public/]twind.config.{ts,js,mjs,cjs}

sastan commented 3 years ago

This inconsistency is confusing indeed, but this will ultimately be fixed when the types don't have to be explicitly listed in the Twind config, right?

I hope so 😄

danielweck commented 3 years ago

I filed this separate issue so that we can track it separately: https://github.com/tw-in-js/typescript-plugin/issues/12 :)

sastan commented 3 years ago
tw`prose(& &:xl lg:xl)`;

&:xl is not valid. It would be expanded to prose:xl. Did you mean xl:&?

danielweck commented 3 years ago

Sorry, just a copy-paste typo. I will correct it right now in my message (dash instead of colon)

danielweck commented 3 years ago

Correction (if I am not mistaken):

tw`prose(& xl lg:xl)`;
danielweck commented 3 years ago

FYI, I have been testing the latest versions of Twind libs. I just want to confirm that without any additional plugin configuration in twind.config.mjs, error highlighting and hover information popup work absolutely fine.

twprose(& xl lg:xl); => prose prose-xl lg:prose-xl

The only feature that requires the additional "manual" Typescript typings is auto-completion:

declare module 'twind' {
    interface Plugins {
        prose: '' | 'xl';
    }
}

I am changing this issue's title to reflect this.