Skip to content

Commit

Permalink
feat: automatically discover icons (egoist#29)
Browse files Browse the repository at this point in the history
* feat: automatically discover icons

* docs: update
  • Loading branch information
hyoban authored Oct 13, 2023
1 parent daaef0a commit 18fcc25
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 14 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module.exports = {
plugins: [
iconsPlugin({
// Select the icon collections you want to use
// You can also ignore this option to automatically discover all icon collections you have installed
collections: getIconCollections(["mdi", "lucide"]),
}),
],
Expand Down
4 changes: 1 addition & 3 deletions example/tailwind.config.cjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module.exports = {
content: ["./index.html"],
plugins: [
require("../dist").iconsPlugin({
collections: require("../dist").getIconCollections(["heroicons"]),
}),
require("../dist").iconsPlugin(),
],
}
6 changes: 4 additions & 2 deletions gen-types.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ const collections = req("@iconify/json/collections.json")

fs.writeFileSync(
"types.ts",
`/** All the available icon collections when you have \`@iconify/json\` installed */\nexport type CollectionNames = ${Object.keys(
`export const availableCollectionNames = [${Object.keys(
collections,
)
.map((v) => JSON.stringify(v))
.join("|")}`,
.join(", ")}] as const
/** All the available icon collections when you have \`@iconify/json\` installed */\nexport type CollectionNames = typeof availableCollectionNames[number]
`,
)
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"build": "pnpm run build-fast --dts-resolve",
"test": "vitest run",
"prepublishOnly": "pnpm run build",
"gen-types": "node ./gen-types.mjs"
"gen-types": "node ./gen-types.mjs",
"prepare": "pnpm run gen-types"
},
"license": "MIT",
"devDependencies": {
Expand Down
6 changes: 6 additions & 0 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ function callerPath(): string | null {
return result[1]
}

export const isPackageExists = (id: string) => {
const p = callerPath()
const cwd = p ? path.dirname(p) : process.cwd()
return Boolean(localResolve(cwd, id))
}

export const getIconCollections = (
include: CollectionNames[] | "all" = "all",
): Record<string, IconifyJSON> => {
Expand Down
48 changes: 48 additions & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,51 @@ test("custom icon", () => {
"
`)
})

test("set collection automatically", () => {
const processor = postcss([
tailwindcss({
config: {
content: [
{
raw: "",
extension: "html",
},
],
plugins: [iconsPlugin()],
},
}),
])

const result = processor.process(`
.foo {
@apply i-heroicons-arrow-left;
}
`)

expect(result.css).toMatchInlineSnapshot(`
"
.foo {
display: inline-block;
width: 1em;
height: 1em;
background-color: currentColor;
-webkit-mask: no-repeat center / 100%;
mask: no-repeat center / 100%;
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
--svg: url(\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18'/%3E%3C/svg%3E\\")
}
"
`)

expect(() => {
processor.process(`
.foo {
@apply i-mdi-home;
}
`).css
}).toThrowErrorMatchingInlineSnapshot(
'"<css input>:3:5: The `i-mdi-home` class does not exist. If `i-mdi-home` is a custom class, make sure it is defined within a `@layer` directive."',
)
})
29 changes: 21 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
import { IconifyJSONIconsData } from "@iconify/types"
import plugin from "tailwindcss/plugin.js"
import { parseIconSet } from "@iconify/utils"
import { generateIconComponent, getIconCollections } from "./core"
import { CollectionNames } from "../types"
import {
generateIconComponent,
getIconCollections,
isPackageExists,
} from "./core"
import { CollectionNames, availableCollectionNames } from "../types"
import { type Optional } from "./utils"
import { IconsOptions } from "./types"

export { getIconCollections, type CollectionNames }

export type IconsPluginOptions = {
collections: Record<string, Optional<IconifyJSONIconsData, "prefix">>
collections?: Record<string, Optional<IconifyJSONIconsData, "prefix">>
} & IconsOptions

export const iconsPlugin = ({
collections,
...options
}: IconsPluginOptions) => {
const { scale = 1, prefix = "i", extraProperties = {} } = options ?? {}
export const iconsPlugin = (iconsPluginOptions?: IconsPluginOptions) => {
const {
collections: propsCollections,
scale = 1,
prefix = "i",
extraProperties = {},
} = iconsPluginOptions ?? {}

const collections =
propsCollections ??
getIconCollections(
availableCollectionNames.filter((name) =>
isPackageExists(`@iconify-json/${name}`),
),
)
const components: Record<string, Record<string, string>> = {}

for (const prefix of Object.keys(collections)) {
Expand Down

0 comments on commit 18fcc25

Please sign in to comment.