diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 139d3ee..0000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -rollup.config.mjs diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 936ba02..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:react/recommended" - ], - "parser": "@typescript-eslint/parser", - "plugins": ["react", "react-hooks", "@typescript-eslint"], - "env": { "browser": true }, - "parserOptions": { - "ecmaVersion": 5, - "sourceType": "module", - "project": "./tsconfig.json" - }, - "rules": { - "@typescript-eslint/indent": ["error", 2], - "quotes": ["error", "single"], - "jsx-quotes": ["error", "prefer-double"], - "semi": [2, "always"], - "eol-last": ["error", "always"], - "no-console": 2, - "no-extra-semi": 2, - "semi-spacing": [2, { "before": false, "after": true }], - "no-dupe-else-if": 0, - "no-setter-return": 0, - "prefer-promise-reject-errors": 0, - "react/button-has-type": 2, - "react/default-props-match-prop-types": 2, - "react/jsx-closing-bracket-location": 2, - "react/jsx-closing-tag-location": 2, - "react/jsx-curly-spacing": 2, - "react/jsx-curly-newline": 2, - "react/jsx-equals-spacing": 2, - "react/jsx-max-props-per-line": [2, { "maximum": 1, "when": "multiline" }], - "react/jsx-first-prop-new-line": 2, - "react/jsx-curly-brace-presence": [ - 2, - { "props": "never", "children": "never" } - ], - "react/jsx-pascal-case": 2, - "react/jsx-props-no-multi-spaces": 2, - "react/jsx-tag-spacing": [2, { "beforeClosing": "never" }], - "react/jsx-wrap-multilines": 2, - "react/no-array-index-key": 2, - "react/no-typos": 2, - "react/no-unsafe": 2, - "react/no-unused-prop-types": 2, - "react/no-unused-state": 2, - "react/self-closing-comp": 2, - "react/sort-comp": 2, - "react/style-prop-object": 2, - "react/void-dom-elements-no-children": 2, - "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks - "react-hooks/exhaustive-deps": "warn" - }, - "settings": { - "react": { - "version": "detect" - } - } -} diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 26d64ab..2bae249 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -1,5 +1,5 @@ name: Checks -on: +on: push: branches: - main @@ -7,9 +7,6 @@ on: branches: - main -env: - NODE: 16 - jobs: prep: if: github.event.pull_request.draft == false @@ -24,10 +21,13 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - name: Use Node.js ${{ env.NODE }} + - name: Read .nvmrc + run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV + + - name: Use Node.js ${{ env.NVMRC }} uses: actions/setup-node@v1 with: - node-version: ${{ env.NODE }} + node-version: ${{ env.NVMRC }} - name: Cache node_modules uses: actions/cache@v2 @@ -47,10 +47,13 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - name: Use Node.js ${{ env.NODE }} + - name: Read .nvmrc + run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV + + - name: Use Node.js ${{ env.NVMRC }} uses: actions/setup-node@v1 with: - node-version: ${{ env.NODE }} + node-version: ${{ env.NVMRC }} - name: Cache node_modules uses: actions/cache@v2 @@ -73,10 +76,13 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - name: Use Node.js ${{ env.NODE }} + - name: Read .nvmrc + run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV + + - name: Use Node.js ${{ env.NVMRC }} uses: actions/setup-node@v1 with: - node-version: ${{ env.NODE }} + node-version: ${{ env.NVMRC }} - name: Cache node_modules uses: actions/cache@v2 @@ -99,10 +105,13 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - name: Use Node.js ${{ env.NODE }} + - name: Read .nvmrc + run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV + + - name: Use Node.js ${{ env.NVMRC }} uses: actions/setup-node@v1 with: - node-version: ${{ env.NODE }} + node-version: ${{ env.NVMRC }} - name: Cache node_modules uses: actions/cache@v2 diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..8fdd954 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22 \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..ee3a689 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +node_modules/ +dist/ +build/ +coverage/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..a95cb05 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": true, + "singleQuote": true, + "trailingComma": "es5", + "printWidth": 100, + "tabWidth": 2 +} diff --git a/.yarnrc.yml b/.yarnrc.yml new file mode 100644 index 0000000..3186f3f --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/README.md b/README.md index 57a931e..1f187da 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # stac-react -React hooks to build front-end applications for STAC APIs. +React hooks to build front-end applications for STAC APIs. > **Note:** -> stac-react is in early development, the API will likely break in future versions. +> stac-react is in early development, the API will likely break in future versions. ## Installation @@ -21,9 +21,9 @@ yarn add @developmentseed/stac-react ## Getting started -Stac-react's hooks must be used inside children of a React context that provides access to the stac-react's core functionality. +Stac-react's hooks must be used inside children of a React context that provides access to the stac-react's core functionality. -To get started, initialize `StacApiProvider` with the base URL of the STAC catalog. +To get started, initialize `StacApiProvider` with the base URL of the STAC catalog. ```jsx import { StacApiProvider } from "stac-react"; @@ -44,14 +44,14 @@ import { StacApiProvider, useCollections } from "stac-react"; function Collections() { const { collections } = useCollections(); - + return ( - - + + ) } @@ -68,7 +68,7 @@ function StacApp() { ### StacApiProvider -Provides the React context required for stac-react hooks. +Provides the React context required for stac-react hooks. #### Initialization @@ -86,9 +86,9 @@ function StacApp() { ##### Component Properties -Option | Type | Description ---------------- | --------- | ------------- -`apiUrl`. | `string` | The base url of the STAC catalog. +| Option | Type | Description | +| --------- | -------- | --------------------------------- | +| `apiUrl`. | `string` | The base url of the STAC catalog. | ### useCollections @@ -97,18 +97,18 @@ Retrieves collections from a STAC catalog. #### Initialization ```js -import { useCollections } from "stac-react"; +import { useCollections } from 'stac-react'; const { collections } = useCollections(); ``` #### Return values -Option | Type | Description ---------------- | --------- | ------------- -`collections` | `array` | A list of collections available from the STAC catalog. Is `null` if collections have not been retrieved. -`state` | `str` | The status of the request. `"IDLE"` before and after the request is sent or received. `"LOADING"` when the request is in progress. -`reload` | `function`| Callback function to trigger a reload of collections. -`error` | [`Error`](#error) | Error information if the last request was unsuccessful. `undefined` if the last request was successful. +| Option | Type | Description | +| ------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `collections` | `array` | A list of collections available from the STAC catalog. Is `null` if collections have not been retrieved. | +| `state` | `str` | The status of the request. `"IDLE"` before and after the request is sent or received. `"LOADING"` when the request is in progress. | +| `reload` | `function` | Callback function to trigger a reload of collections. | +| `error` | [`Error`](#error) | Error information if the last request was unsuccessful. `undefined` if the last request was successful. | #### Example @@ -141,52 +141,52 @@ function CollectionList() { ### useCollection -Retrieves a single collection from the STAC catalog. +Retrieves a single collection from the STAC catalog. #### Initialization ```js -import { useCollection } from "stac-react"; +import { useCollection } from 'stac-react'; const { collection } = useCollection(id); ``` #### Parameters -Option | Type | Description ---------------- | --------- | ------------- -`id` | `string` | The collection ID. +| Option | Type | Description | +| ------ | -------- | ------------------ | +| `id` | `string` | The collection ID. | #### Return values -Option | Type | Description ---------------- | --------- | ------------- -`collection` | `object` | The collection matching the provided ID. Is `null` if collection has not been retrieved. -`state` | `str` | The status of the request. `"IDLE"` before and after the request is sent or received. `"LOADING"` when the request is in progress. -`reload` | `function`| Callback function to trigger a reload of the collection. -`error` | [`Error`](#error) | Error information if the last request was unsuccessful. `undefined` if the last request was successful. +| Option | Type | Description | +| ------------ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `collection` | `object` | The collection matching the provided ID. Is `null` if collection has not been retrieved. | +| `state` | `str` | The status of the request. `"IDLE"` before and after the request is sent or received. `"LOADING"` when the request is in progress. | +| `reload` | `function` | Callback function to trigger a reload of the collection. | +| `error` | [`Error`](#error) | Error information if the last request was unsuccessful. `undefined` if the last request was successful. | #### Example ```js -import { useCollection } from "stac-react"; +import { useCollection } from 'stac-react'; function Collection() { - const { collection, state } = useCollection("collection_id"); + const { collection, state } = useCollection('collection_id'); - if (state === "LOADING") { - return

Loading collection...

+ if (state === 'LOADING') { + return

Loading collection...

; } return ( <> - {collection ? ( - <> -

{collection.id}

-

{collection.description}

- - ) : ( -

Not found

- )} + {collection ? ( + <> +

{collection.id}

+

{collection.description}

+ + ) : ( +

Not found

+ )} ); } @@ -199,47 +199,47 @@ Retrieves an item from the STAC catalog. To retrieve an item, provide its full u #### Initialization ```js -import { useItem } from "stac-react"; +import { useItem } from 'stac-react'; const { item } = useItem(url); ``` #### Parameters -Option | Type | Description ---------------- | --------- | ------------- -`url` | `string` | The URL of the item you want to retrieve. +| Option | Type | Description | +| ------ | -------- | ----------------------------------------- | +| `url` | `string` | The URL of the item you want to retrieve. | #### Return values -Option | Type | Description ---------------- | --------- | ------------- -`item` | `object` | The item matching the provided URL. -`state` | `str` | The status of the request. `"IDLE"` before and after the request is sent or received. `"LOADING"` when the request is in progress. -`reload` | `function`| Callback function to trigger a reload of the item. -`error` | [`Error`](#error) | Error information if the last request was unsuccessful. `undefined` if the last request was successful. +| Option | Type | Description | +| -------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `item` | `object` | The item matching the provided URL. | +| `state` | `str` | The status of the request. `"IDLE"` before and after the request is sent or received. `"LOADING"` when the request is in progress. | +| `reload` | `function` | Callback function to trigger a reload of the item. | +| `error` | [`Error`](#error) | Error information if the last request was unsuccessful. `undefined` if the last request was successful. | #### Examples ```js -import { useItem } from "stac-react"; +import { useItem } from 'stac-react'; function Item() { - const { item, state } = useItem("https://stac-catalog.com/items/abc123"); + const { item, state } = useItem('https://stac-catalog.com/items/abc123'); - if (state === "LOADING") { - return

Loading item...

+ if (state === 'LOADING') { + return

Loading item...

; } return ( <> - {item ? ( - <> -

{item.id}

-

{items.description}

- - ) : ( -

Not found

- )} + {item ? ( + <> +

{item.id}

+

{items.description}

+ + ) : ( +

Not found

+ )} ); } @@ -252,41 +252,41 @@ Executes a search against a STAC API using the provided search parameters. #### Initialization ```js -import { useStacSearch } from "stac-react"; +import { useStacSearch } from 'stac-react'; const { results } = useStacSearch(); ``` #### Return values -Option | Type | Description ------------------- | --------- | ------------- -`submit` | `function` | Callback to submit the search using the current filter parameters. Excecutes an API call to the specified STAC API. -`ids` | `array` | List of item IDs to match in the search, `undefined` if unset. -`setIds(itemIds)` | `function` | Callback to set `ids`. `itemIds` must be an `array` of `string` with the IDs of the selected items, or `undefined` to reset. -`bbox` | `array` | Array of coordinates `[northWestLon, northWestLat, southEastLon, southEastLat]`, `undefined` if unset. -`setBbox(bbox)` | `function` | Callback to set `bbox`. `bbox` must be an array of coordinates `[northWestLon, northWestLat, southEastLon, southEastLat]`, or `undefined` to reset. -`collections` | `array` | List of select collection IDs included in the search query. `undefined` if unset. -`setCollections(collectionIDs)` | `function` | Callback to set `collections`. `collectionIDs` must be an `array` of `string` with the IDs of the selected collections, or `undefined` to reset. -`dateRangeFrom` | `string` | The from-date of the search query. `undefined` if unset. -`setDateRangeFrom(fromDate)` | `function` | Callback to set `dateRangeFrom`. `fromDate` must be ISO representation of a date, ie. `2022-05-18`, or `undefined` to reset. -`dateRangeTo` | `string` | The to-date of the search query. `undefined` if unset. -`setDateRangeTo(toDate)` | `function` | Callback to set `dateRangeto`. `toDate` must be ISO representation of a date, ie. `2022-05-18`, or `undefined` to reset. -`sortby` | `array` | Specifies the order of results. Array of `{ field: string, direction: 'asc' | 'desc' }` -`setSortby(sort)` | `function` | Callback to set `sortby`. `sort` must be an array of `{ field: string, direction: 'asc' | 'desc' }`, or `undefined` to reset. -`limit` | `number` | The number of results returned per result page. -`setLimit(limit)` | `function` | Callback to set `limit`. `limit` must be a `number`, or `undefined` to reset. -`results` | `object` | The result of the last search query; a [GeoJSON `FeatureCollection` with additional members](https://github.com/radiantearth/stac-api-spec/blob/v1.0.0-rc.2/fragments/itemcollection/README.md). `undefined` if the search request has not been submitted, or if there was an error. -`state` | `string` | The status of the request. `"IDLE"` before and after the request is sent or received. `"LOADING"` when the request is in progress. -`error` | [`Error`](#error) | Error information if the last request was unsuccessful. `undefined` if the last request was successful. -`nextPage` | `function` | Callback function to load the next page of results. Is `undefined` if the last page is the currently loaded. -`previousPage` | `function` | Callback function to load the previous page of results. Is `undefined` if the first page is the currently loaded. +| Option | Type | Description | +| ------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------- | +| `submit` | `function` | Callback to submit the search using the current filter parameters. Excecutes an API call to the specified STAC API. | +| `ids` | `array` | List of item IDs to match in the search, `undefined` if unset. | +| `setIds(itemIds)` | `function` | Callback to set `ids`. `itemIds` must be an `array` of `string` with the IDs of the selected items, or `undefined` to reset. | +| `bbox` | `array` | Array of coordinates `[northWestLon, northWestLat, southEastLon, southEastLat]`, `undefined` if unset. | +| `setBbox(bbox)` | `function` | Callback to set `bbox`. `bbox` must be an array of coordinates `[northWestLon, northWestLat, southEastLon, southEastLat]`, or `undefined` to reset. | +| `collections` | `array` | List of select collection IDs included in the search query. `undefined` if unset. | +| `setCollections(collectionIDs)` | `function` | Callback to set `collections`. `collectionIDs` must be an `array` of `string` with the IDs of the selected collections, or `undefined` to reset. | +| `dateRangeFrom` | `string` | The from-date of the search query. `undefined` if unset. | +| `setDateRangeFrom(fromDate)` | `function` | Callback to set `dateRangeFrom`. `fromDate` must be ISO representation of a date, ie. `2022-05-18`, or `undefined` to reset. | +| `dateRangeTo` | `string` | The to-date of the search query. `undefined` if unset. | +| `setDateRangeTo(toDate)` | `function` | Callback to set `dateRangeto`. `toDate` must be ISO representation of a date, ie. `2022-05-18`, or `undefined` to reset. | +| `sortby` | `array` | Specifies the order of results. Array of `{ field: string, direction: 'asc' | 'desc' }` | +| `setSortby(sort)` | `function` | Callback to set `sortby`. `sort` must be an array of `{ field: string, direction: 'asc' | 'desc' }`, or `undefined` to reset. | +| `limit` | `number` | The number of results returned per result page. | +| `setLimit(limit)` | `function` | Callback to set `limit`. `limit` must be a `number`, or `undefined` to reset. | +| `results` | `object` | The result of the last search query; a [GeoJSON `FeatureCollection` with additional members](https://github.com/radiantearth/stac-api-spec/blob/v1.0.0-rc.2/fragments/itemcollection/README.md). `undefined` if the search request has not been submitted, or if there was an error. | +| `state` | `string` | The status of the request. `"IDLE"` before and after the request is sent or received. `"LOADING"` when the request is in progress. | +| `error` | [`Error`](#error) | Error information if the last request was unsuccessful. `undefined` if the last request was successful. | +| `nextPage` | `function` | Callback function to load the next page of results. Is `undefined` if the last page is the currently loaded. | +| `previousPage` | `function` | Callback function to load the previous page of results. Is `undefined` if the first page is the currently loaded. | #### Examples ##### Render results ```jsx -import { useStacSearch } from "stac-react"; +import { useStacSearch } from 'stac-react'; function StacComponent() { const { result } = useStacSearch(); @@ -297,23 +297,23 @@ function StacComponent() { {results && (
    {results.features.map(({ id }) => ( -
  • { id }
  • +
  • {id}
  • ))}
)} - ) + ); } ``` ##### Handle errors ```jsx -import { useCallback } from "react"; -import { useStacSearch } from "stac-react"; +import { useCallback } from 'react'; +import { useStacSearch } from 'stac-react'; -import Map from "./map"; +import Map from './map'; function StacComponent() { const { error, result } = useStacSearch(); @@ -321,17 +321,17 @@ function StacComponent() { return ( <>
- {error &&

{ error.detail }

} + {error &&

{error.detail}

} {results && (
    {results.features.map(({ id }) => ( -
  • { id }
  • +
  • {id}
  • ))}
)}
- ) + ); } ``` @@ -389,7 +389,7 @@ function StacComponent() {
Select collections {collections.map(({ id, title }) => ( - { - setIsBboxDrawEnabled(false); - - const { coordinates } = feature.geometry; - const bbox = [...coordinates[0][0], ...coordinates[0][2]]; - setBbox(bbox); - }, [setBbox]); + const handleDrawComplete = useCallback( + (feature) => { + setIsBboxDrawEnabled(false); + + const { coordinates } = feature.geometry; + const bbox = [...coordinates[0][0], ...coordinates[0][2]]; + setBbox(bbox); + }, + [setBbox] + ); - + ; } ``` @@ -467,12 +470,11 @@ function StacComponent() { } ``` -Option | Type | Description ------------------- | --------- | ------------- -`detail` | `string` | `object | The error return from the API. Either a `string` or and `object` depending on the response. -`status` | `number` | HTTP status code of the response. -`statusText` | `string` | Status text for the response. - +| Option | Type | Description | +| ------------ | -------- | --------------------------------- | ------------------------------------------------------------------------------------------- | +| `detail` | `string` | `object | The error return from the API. Either a`string` or and `object` depending on the response. | +| `status` | `number` | HTTP status code of the response. | +| `statusText` | `string` | Status text for the response. | ## Development diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..c626fb0 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,102 @@ +import globals from 'globals'; +import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import react from 'eslint-plugin-react'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; +import prettier from 'eslint-plugin-prettier/recommended'; +import { defineConfig, globalIgnores } from 'eslint/config'; + +const customRules = { + // Helps with cleaning debug statements by erroring on console. + 'no-console': 'error', + // It's no longer needed to import React, so this just prevents weird + // errors when you don't. + 'react/react-in-jsx-scope': 'off', + // Array indexes as keys should not be used. The occasional time it is + // needed, an ignore can be added. + 'react/no-array-index-key': 'error', + // Helps with enforcing rules of hooks. Very helpful to catch wrongly + // placed hooks, like conditional usage. + 'react-hooks/rules-of-hooks': 'error', + // Ensure that components are PascalCase + 'react/jsx-pascal-case': 'error', + // Force self closing components when there are no children. + // Prevents `` + 'react/self-closing-comp': 'error', +}; + +export default defineConfig([ + globalIgnores(['dist', 'node_modules', 'build', 'coverage']), + js.configs.recommended, + react.configs.flat.recommended, + prettier, + // JS/JSX config + { + files: ['**/*.{js,jsx,mjs,cjs}'], + languageOptions: { + ecmaVersion: 2020, + globals: { ...globals.browser, process: 'readonly' }, + }, + settings: { react: { version: 'detect' } }, + plugins: { + react, + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...customRules, + 'no-unused-vars': [ + 'error', + { + args: 'all', + argsIgnorePattern: '^_', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_', + destructuredArrayIgnorePattern: '^_', + varsIgnorePattern: '^_', + ignoreRestSiblings: true, + }, + ], + }, + }, + // TS/TSX config + { + files: ['**/*.{ts,tsx}'], + extends: [...tseslint.configs.recommendedTypeChecked], + languageOptions: { + parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname }, + ecmaVersion: 2020, + globals: { ...globals.browser, process: 'readonly' }, + }, + settings: { react: { version: 'detect' } }, + plugins: { + ...tseslint.plugins, + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...customRules, + '@typescript-eslint/no-unused-vars': [ + 'error', + { + args: 'all', + argsIgnorePattern: '^_', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_', + destructuredArrayIgnorePattern: '^_', + varsIgnorePattern: '^_', + ignoreRestSiblings: true, + }, + ], + // TODO: Consider making these errors in the future (use recommendedTypeChecked rules!). + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unsafe-assignment': 'warn', + '@typescript-eslint/no-unsafe-call': 'warn', + '@typescript-eslint/no-unsafe-member-access': 'warn', + '@typescript-eslint/no-unsafe-return': 'warn', + '@typescript-eslint/no-unsafe-argument': 'warn', + '@typescript-eslint/no-unsafe-enum-comparison': 'warn', + }, + }, +]); diff --git a/example/package.json b/example/package.json index 75e8e18..e91636b 100644 --- a/example/package.json +++ b/example/package.json @@ -23,12 +23,6 @@ "test": "react-scripts test", "eject": "react-scripts eject" }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, "browserslist": { "production": [ ">0.2%", diff --git a/example/postcss.config.js b/example/postcss.config.js index 33ad091..adbcb51 100644 --- a/example/postcss.config.js +++ b/example/postcss.config.js @@ -1,6 +1,7 @@ +/* global module */ module.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, }, -} +}; diff --git a/example/public/index.html b/example/public/index.html index aa069f2..d79d7a7 100644 --- a/example/public/index.html +++ b/example/public/index.html @@ -1,14 +1,11 @@ - + - +