@menapo/icons 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +35 -2
- package/dist/index.d.ts +52 -0
- package/dist/index.js +6 -0
- package/dist/vite.d.ts +69 -0
- package/dist/vite.js +2624 -0
- package/package.json +62 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 menapo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,36 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @menapo/icons
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Icons as one typed call: `icon("lucide:check")` returns an element's
|
|
4
|
+
attributes, and the Vite plugin compiles it to a literal and adds that
|
|
5
|
+
icon's CSS, a mask in `currentColor` or a coloured background, to the module
|
|
6
|
+
that names it. Zero runtime JavaScript, zero config, the same call in React,
|
|
7
|
+
Preact, Vue, Svelte, Solid, Astro, plain code and markup templates.
|
|
8
|
+
|
|
9
|
+
**Status: built, private until 1.0.** `icon()` with `label` and `class`, the
|
|
10
|
+
plugin (sets detected from `@iconify-json/*`, local SVG folders, per-module
|
|
11
|
+
CSS, `icons.d.ts`, errors with the closest names, dev updates) and
|
|
12
|
+
`resolveIcon`/`iconName` for og are implemented and tested;
|
|
13
|
+
`examples/icons-react` checks React, Vue and plain code in Chromium. The
|
|
14
|
+
release waits on the owner's review.
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
// vite.config.ts
|
|
18
|
+
import { icons } from "@menapo/icons/vite";
|
|
19
|
+
|
|
20
|
+
export default defineConfig({ plugins: [icons()] });
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { icon } from "@menapo/icons";
|
|
25
|
+
|
|
26
|
+
<span {...icon("lucide:check")} />;
|
|
27
|
+
<button>
|
|
28
|
+
<span {...icon("lucide:x", { label: t("Close") })} />
|
|
29
|
+
</button>;
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- [Guide](./docs/guide/README.md): setup, labels, colour and size, runtime
|
|
33
|
+
choices, your own SVGs, every framework, and the reference.
|
|
34
|
+
- [Plan](./docs/PLAN.md): the design, its decisions and measurements.
|
|
35
|
+
- Benchmark: `vp run --filter @menapo/icons bench` (CSS bytes against
|
|
36
|
+
Iconify's own generator and inline SVG, parse and compile time).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* `@menapo/icons` (PLAN §0): `icon("lucide:x")` and its types. The plugin
|
|
4
|
+
* (`@menapo/icons/vite`) replaces every call with a literal object and
|
|
5
|
+
* imports the icon's CSS, so compiled code never calls the function below
|
|
6
|
+
* and no JavaScript of this package reaches the browser (D2).
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Filled by the generated `icons.d.ts` (D10): the installed names and the
|
|
10
|
+
* project's framework, the way vicss's `vicss.d.ts` registers its own.
|
|
11
|
+
*/
|
|
12
|
+
export interface Register {}
|
|
13
|
+
/** Every icon the project can name: `"lucide:check" | … | "brand:logo"`. */
|
|
14
|
+
export type IconName = Register extends {
|
|
15
|
+
names: infer N extends string;
|
|
16
|
+
} ? N : `${string}:${string}`;
|
|
17
|
+
/** The framework the generated types registered: React when none is. */
|
|
18
|
+
type RegisteredFramework = Register extends {
|
|
19
|
+
framework: infer F extends string;
|
|
20
|
+
} ? F : "react";
|
|
21
|
+
/** React takes `className`; every other framework and kit's markup take `class` (D3). */
|
|
22
|
+
type ClassAttribute = RegisteredFramework extends "react" ? "className" : "class";
|
|
23
|
+
export interface IconOptions {
|
|
24
|
+
/**
|
|
25
|
+
* The icon carries meaning on its own: it gets `role="img"` and this
|
|
26
|
+
* `aria-label` instead of `aria-hidden`. Translate it: `t("Close")`.
|
|
27
|
+
*/
|
|
28
|
+
readonly label?: string;
|
|
29
|
+
/** More classes, appended to the icon's: `"size-5 text-red-700"`, `sx(style).className`. */
|
|
30
|
+
readonly class?: string;
|
|
31
|
+
}
|
|
32
|
+
/** A decorative icon's attributes: hidden from assistive technology. */
|
|
33
|
+
export type DecorativeIcon = { readonly [K in ClassAttribute]: string; } & {
|
|
34
|
+
readonly "aria-hidden": "true";
|
|
35
|
+
};
|
|
36
|
+
/** A labelled icon's attributes: an image with an accessible name. */
|
|
37
|
+
export type LabelledIcon = { readonly [K in ClassAttribute]: string; } & {
|
|
38
|
+
readonly role: "img";
|
|
39
|
+
readonly "aria-label": string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The attributes of an icon element: spread them on an empty element,
|
|
43
|
+
* `<span {...icon("lucide:check")} />`. The name is a string literal, so
|
|
44
|
+
* the plugin can compile it; a name chosen at runtime picks from an object
|
|
45
|
+
* of compiled calls.
|
|
46
|
+
*/
|
|
47
|
+
export declare function icon(name: IconName, options: IconOptions & {
|
|
48
|
+
readonly label: string;
|
|
49
|
+
}): LabelledIcon;
|
|
50
|
+
export declare function icon(name: IconName, options?: IconOptions): DecorativeIcon;
|
|
51
|
+
//#endregion
|
|
52
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/index.ts
|
|
2
|
+
function icon(name) {
|
|
3
|
+
throw new Error(`@menapo/icons: icon(${JSON.stringify(name)}) ran uncompiled. Add icons() from "@menapo/icons/vite" to the Vite config's plugins, and write the name as a string literal.`);
|
|
4
|
+
}
|
|
5
|
+
//#endregion
|
|
6
|
+
export { icon };
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
//#region src/vite/svg.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The SVG work both kinds of source share (D5, D13): cleaning a local file,
|
|
5
|
+
* reading its size, and deciding whether it is monochrome. Plain strings
|
|
6
|
+
* in and out, so it is unit-tested without files.
|
|
7
|
+
*/
|
|
8
|
+
/** One icon, ready for CSS or for inlining. */
|
|
9
|
+
interface Svg {
|
|
10
|
+
/** The inner markup, with black painted in `currentColor` for a monochrome icon. */
|
|
11
|
+
readonly body: string;
|
|
12
|
+
readonly width: number;
|
|
13
|
+
readonly height: number;
|
|
14
|
+
/** Painted in `currentColor` (a mask), or keeping its own colours (a background). */
|
|
15
|
+
readonly mono: boolean;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/vite/resolve.d.ts
|
|
19
|
+
/** A resolved icon, with the file it came from (watched in dev). */
|
|
20
|
+
interface ResolvedIcon extends Svg {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly file: string;
|
|
23
|
+
}
|
|
24
|
+
interface IconSourceOptions {
|
|
25
|
+
/** The project root: its `package.json` lists the sets. */
|
|
26
|
+
readonly root: string;
|
|
27
|
+
/** Local sets: a prefix mapped to a directory, relative to the root. */
|
|
28
|
+
readonly folders?: Readonly<Record<string, string>> | undefined;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/vite/index.d.ts
|
|
32
|
+
export interface IconsOptions {
|
|
33
|
+
/**
|
|
34
|
+
* The app's own SVGs: a set name mapped to a directory, relative to the
|
|
35
|
+
* root. `{ brand: "./src/icons" }` makes `src/icons/logo.svg` the icon
|
|
36
|
+
* `brand:logo`, and `arrows/left.svg` the icon `brand:arrows-left`.
|
|
37
|
+
* Installed `@iconify-json/*` sets need no option.
|
|
38
|
+
*/
|
|
39
|
+
readonly folders?: Readonly<Record<string, string>>;
|
|
40
|
+
}
|
|
41
|
+
/** `plugins: [icons()]` in a Vite config. */
|
|
42
|
+
export declare function icons(options?: IconsOptions): Plugin;
|
|
43
|
+
/** The plugin's `api`: a renderer under it resolves the folders it was given. */
|
|
44
|
+
export interface IconsApi {
|
|
45
|
+
readonly folders: IconsOptions["folders"];
|
|
46
|
+
}
|
|
47
|
+
/** An icon for a renderer that inlines SVG: og (D11), email later. */
|
|
48
|
+
export interface InlineIcon extends ResolvedIcon {
|
|
49
|
+
/** The whole `<svg>` element; a monochrome icon paints in `currentColor`. */
|
|
50
|
+
readonly svg: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* `lucide:check` to its SVG, from the sets and folders of the project at
|
|
54
|
+
* `root`, as the plugin resolves it. Throws a message naming the fix for an
|
|
55
|
+
* unknown name. Build side only: og calls it while it renders.
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveIcon(name: string, options: IconSourceOptions): InlineIcon;
|
|
58
|
+
/**
|
|
59
|
+
* The name an `icon()` result stands for, read back from its classes:
|
|
60
|
+
* `iconName({ class: "mi mi-lucide--x" })` is `"lucide:x"`. A spread in a
|
|
61
|
+
* markup template is just attributes; this is how a renderer knows it is
|
|
62
|
+
* an icon. Takes `class` or `className` (D3).
|
|
63
|
+
*/
|
|
64
|
+
export declare function iconName(attributes: {
|
|
65
|
+
readonly class?: unknown;
|
|
66
|
+
readonly className?: unknown;
|
|
67
|
+
}): string | undefined;
|
|
68
|
+
//#endregion
|
|
69
|
+
export type { ResolvedIcon };
|