Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 37 additions & 11 deletions plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,31 +361,57 @@ Available client types:
> [!NOTE]
> If your project also uses `vite/client` types, its `*.svg` declaration (which types SVGs as `string`) may conflict with the plugin's component types.

### Custom module declarations
### Typing an icon

TypeScript can't match two wildcards in a module specifier, so named sprite queries (`?sprite=name`) and combined query params (`?current-color&sprite=icons`) aren't covered by the built-in declarations. Add your own in a `.d.ts` file included by your tsconfig:
Each target exports its component type as `SvgComponent` from `@svg-jar/plugin/types/<target>`. Use it to type a variable, prop or config field that holds an SVG import, instead of writing out the type yourself.

```ts
// svg.d.ts (React example)
declare module '*.svg?sprite=icons' {
import type { FC, SVGAttributes, ReactNode } from 'react';
// sidebar.ts (Ember example)
import type { SvgComponent } from '@svg-jar/plugin/types/ember';
import UsersIcon from './icons/users.svg';

const Component: FC<SVGAttributes<SVGSVGElement> & { children?: ReactNode }>;
export default Component;
interface Section {
title: string;
icon: SvgComponent;
}

export const sections: Section[] = [{ title: 'Users', icon: UsersIcon }];
```

For the `dom` target:
```tsx
// React example
import type { SvgComponent } from '@svg-jar/plugin/types/react';

function NavLink({ href, icon: Icon, label }: { href: string; icon: SvgComponent; label: string }) {
return (
<a href={href}>
<Icon aria-hidden="true" />
{label}
</a>
);
}
```

The `dom` target also exports `SvgOptions`, the options type its factory function accepts.

Importing from `@svg-jar/plugin/types/<target>` only gives you the types. The `*.svg` module declarations still come from the `client` entry in your tsconfig.

### Custom module declarations

TypeScript can't match two wildcards in a module specifier, so named sprite queries (`?sprite=name`) and combined query params (`?current-color&sprite=icons`) aren't covered by the built-in declarations. Add your own in a `.d.ts` file included by your tsconfig:

```ts
// svg.d.ts (Ember example)
declare module '*.svg?sprite=icons' {
import type { SvgOptions } from '@svg-jar/plugin/runtime/dom';
import type { SvgComponent } from '@svg-jar/plugin/types/ember';

const component: (options?: SvgOptions) => SVGSVGElement;
export default component;
const Component: SvgComponent;
export default Component;
}
```

For other targets, change `ember` in the import path to your target, e.g. `@svg-jar/plugin/types/react`.

The `?file` query always exports a `string` URL regardless of target, so no custom declaration is needed for combined file queries.

## How it works
Expand Down
23 changes: 23 additions & 0 deletions plugin/client/dom-types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Named types for SVG imports handled by @svg-jar/plugin with the DOM target.
//
// import type { SvgComponent } from '@svg-jar/plugin/types/dom';
//
// This file only exports types. To type the `*.svg` imports themselves, add
// "@svg-jar/plugin/client/dom" to "types" in your tsconfig.json.

/**
* Options for the rendered SVG element. `title` and `desc` create child
* elements for accessibility. Any other property is set as an attribute on
* the `<svg>` element.
*/
export interface SvgOptions {
/** Creates a `<title>` child element for accessibility. */
title?: string;
/** Creates a `<desc>` child element for accessibility. */
desc?: string;
/** Any other properties are set as attributes on the `<svg>` element. */
[attr: string]: string | undefined;
}

/** Factory function that creates a new SVG DOM element on each call. */
export type SvgComponent = (options?: SvgOptions) => SVGSVGElement;
36 changes: 18 additions & 18 deletions plugin/client/dom.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,35 @@
// "types": ["@svg-jar/plugin/client/dom"]
// }
// }

interface SvgOptions {
/** Creates a `<title>` child element for accessibility. */
title?: string;
/** Creates a `<desc>` child element for accessibility. */
desc?: string;
/** Any other properties are set as attributes on the `<svg>` element. */
[attr: string]: string | undefined;
}
//
// The component type is exported by name from "@svg-jar/plugin/types/dom".

declare module '*.svg' {
/** Factory function that creates a new SVG DOM element on each call. */
const component: (options?: SvgOptions) => SVGSVGElement;
export default component;
import type { SvgComponent } from '@svg-jar/plugin/types/dom';

const Component: SvgComponent;
export default Component;
}

declare module '*.svg?current-color' {
const component: (options?: SvgOptions) => SVGSVGElement;
export default component;
import type { SvgComponent } from '@svg-jar/plugin/types/dom';

const Component: SvgComponent;
export default Component;
}

declare module '*.svg?skip-current-color' {
const component: (options?: SvgOptions) => SVGSVGElement;
export default component;
import type { SvgComponent } from '@svg-jar/plugin/types/dom';

const Component: SvgComponent;
export default Component;
}

declare module '*.svg?unsafe-inline' {
const component: (options?: SvgOptions) => SVGSVGElement;
export default component;
import type { SvgComponent } from '@svg-jar/plugin/types/dom';

const Component: SvgComponent;
export default Component;
}

declare module '*.svg?file' {
Expand Down
16 changes: 16 additions & 0 deletions plugin/client/ember-types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Named types for SVG imports handled by @svg-jar/plugin with the Ember target.
//
// import type { SvgComponent } from '@svg-jar/plugin/types/ember';
//
// This file only exports types. To type the `*.svg` imports themselves, add
// "@svg-jar/plugin/client/ember" to "types" in your tsconfig.json.

import type { ComponentLike } from '@glint/template';

/** Ember component that renders an SVG import. */
export type SvgComponent = ComponentLike<{
Element: SVGSVGElement;
Blocks: {
default: [];
};
}>;
46 changes: 14 additions & 32 deletions plugin/client/ember.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,52 +7,34 @@
// "types": ["@svg-jar/plugin/client/ember"]
// }
// }
//
// The component type is exported by name from "@svg-jar/plugin/types/ember".

declare module '*.svg' {
import type { ComponentLike } from '@glint/template';

const Component: ComponentLike<{
Element: SVGSVGElement;
Blocks: {
default: [];
};
}>;
import type { SvgComponent } from '@svg-jar/plugin/types/ember';

const Component: SvgComponent;
export default Component;
}

declare module '*.svg?current-color' {
import type { ComponentLike } from '@glint/template';

const Component: ComponentLike<{
Element: SVGSVGElement;
Blocks: {
default: [];
};
}>;
import type { SvgComponent } from '@svg-jar/plugin/types/ember';

const Component: SvgComponent;
export default Component;
}

declare module '*.svg?skip-current-color' {
import type { ComponentLike } from '@glint/template';

const Component: ComponentLike<{
Element: SVGSVGElement;
Blocks: {
default: [];
};
}>;
import type { SvgComponent } from '@svg-jar/plugin/types/ember';

const Component: SvgComponent;
export default Component;
}

declare module '*.svg?unsafe-inline' {
import type { ComponentLike } from '@glint/template';

const Component: ComponentLike<{
Element: SVGSVGElement;
Blocks: {
default: [];
};
}>;
import type { SvgComponent } from '@svg-jar/plugin/types/ember';

const Component: SvgComponent;
export default Component;
}

Expand Down
11 changes: 11 additions & 0 deletions plugin/client/preact-types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Named types for SVG imports handled by @svg-jar/plugin with the Preact target.
//
// import type { SvgComponent } from '@svg-jar/plugin/types/preact';
//
// This file only exports types. To type the `*.svg` imports themselves, add
// "@svg-jar/plugin/client/preact" to "types" in your tsconfig.json.

import type { FunctionComponent, JSX } from 'preact';

/** Preact component that renders an SVG import. */
export type SvgComponent = FunctionComponent<JSX.SVGAttributes<SVGSVGElement>>;
18 changes: 10 additions & 8 deletions plugin/client/preact.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,34 @@
// "types": ["@svg-jar/plugin/client/preact"]
// }
// }
//
// The component type is exported by name from "@svg-jar/plugin/types/preact".

declare module '*.svg' {
import type { FunctionComponent, JSX } from 'preact';
import type { SvgComponent } from '@svg-jar/plugin/types/preact';

const Component: FunctionComponent<JSX.SVGAttributes<SVGSVGElement>>;
const Component: SvgComponent;
export default Component;
}

declare module '*.svg?current-color' {
import type { FunctionComponent, JSX } from 'preact';
import type { SvgComponent } from '@svg-jar/plugin/types/preact';

const Component: FunctionComponent<JSX.SVGAttributes<SVGSVGElement>>;
const Component: SvgComponent;
export default Component;
}

declare module '*.svg?skip-current-color' {
import type { FunctionComponent, JSX } from 'preact';
import type { SvgComponent } from '@svg-jar/plugin/types/preact';

const Component: FunctionComponent<JSX.SVGAttributes<SVGSVGElement>>;
const Component: SvgComponent;
export default Component;
}

declare module '*.svg?unsafe-inline' {
import type { FunctionComponent, JSX } from 'preact';
import type { SvgComponent } from '@svg-jar/plugin/types/preact';

const Component: FunctionComponent<JSX.SVGAttributes<SVGSVGElement>>;
const Component: SvgComponent;
export default Component;
}

Expand Down
11 changes: 11 additions & 0 deletions plugin/client/react-types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Named types for SVG imports handled by @svg-jar/plugin with the React target.
//
// import type { SvgComponent } from '@svg-jar/plugin/types/react';
//
// This file only exports types. To type the `*.svg` imports themselves, add
// "@svg-jar/plugin/client/react" to "types" in your tsconfig.json.

import type { FC, SVGAttributes, ReactNode } from 'react';

/** React component that renders an SVG import. */
export type SvgComponent = FC<SVGAttributes<SVGSVGElement> & { children?: ReactNode }>;
18 changes: 10 additions & 8 deletions plugin/client/react.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,34 @@
// "types": ["@svg-jar/plugin/client/react"]
// }
// }
//
// The component type is exported by name from "@svg-jar/plugin/types/react".

declare module '*.svg' {
import type { FC, SVGAttributes, ReactNode } from 'react';
import type { SvgComponent } from '@svg-jar/plugin/types/react';

const Component: FC<SVGAttributes<SVGSVGElement> & { children?: ReactNode }>;
const Component: SvgComponent;
export default Component;
}

declare module '*.svg?current-color' {
import type { FC, SVGAttributes, ReactNode } from 'react';
import type { SvgComponent } from '@svg-jar/plugin/types/react';

const Component: FC<SVGAttributes<SVGSVGElement> & { children?: ReactNode }>;
const Component: SvgComponent;
export default Component;
}

declare module '*.svg?skip-current-color' {
import type { FC, SVGAttributes, ReactNode } from 'react';
import type { SvgComponent } from '@svg-jar/plugin/types/react';

const Component: FC<SVGAttributes<SVGSVGElement> & { children?: ReactNode }>;
const Component: SvgComponent;
export default Component;
}

declare module '*.svg?unsafe-inline' {
import type { FC, SVGAttributes, ReactNode } from 'react';
import type { SvgComponent } from '@svg-jar/plugin/types/react';

const Component: FC<SVGAttributes<SVGSVGElement> & { children?: ReactNode }>;
const Component: SvgComponent;
export default Component;
}

Expand Down
11 changes: 11 additions & 0 deletions plugin/client/solid-types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Named types for SVG imports handled by @svg-jar/plugin with the Solid target.
//
// import type { SvgComponent } from '@svg-jar/plugin/types/solid';
//
// This file only exports types. To type the `*.svg` imports themselves, add
// "@svg-jar/plugin/client/solid" to "types" in your tsconfig.json.

import type { Component, JSX, ParentProps } from 'solid-js';

/** Solid component that renders an SVG import. */
export type SvgComponent = Component<ParentProps<JSX.SvgSVGAttributes<SVGSVGElement>>>;
Loading
Loading