@dubium/icons 0.0.2-alpha.1 → 0.0.2-alpha.3
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/README.md +101 -0
- package/dist/collection/Icon123Icon.d.ts +3 -0
- package/dist/collection/Icon123Icon.js +18 -0
- package/dist/collection/Icon24HoursIcon.d.ts +3 -0
- package/dist/collection/Icon24HoursIcon.js +18 -0
- package/dist/collection/Icon2faIcon.d.ts +3 -0
- package/dist/collection/Icon2faIcon.js +18 -0
- package/dist/collection/Icon360Icon.d.ts +3 -0
- package/dist/collection/Icon360Icon.js +18 -0
- package/dist/collection/Icon360ViewIcon.d.ts +3 -0
- package/dist/collection/Icon360ViewIcon.js +18 -0
- package/dist/collection/index.d.ts +5 -1
- package/dist/collection/index.js +6 -0
- package/dist/collection/types.d.ts +2 -7
- package/dist/spa/icon/Icon.d.ts +7 -39
- package/dist/spa/icon/Icon.js +34 -40
- package/dist/spa/icon/Icon.registry.d.ts +6 -2
- package/dist/spa/provider/IconProvider.js +4 -4
- package/dist/ssr/icon/Icon.js +9 -8
- package/dist/ssr/icon/Icon.registry.d.ts +6 -2
- package/dist/ssr/icon/Icon.registry.js +7 -1
- package/dist/ssr/icon/Icon.types.d.ts +4 -0
- package/dist/vite/index.d.ts +50 -0
- package/dist/vite/index.js +167 -0
- package/package.json +21 -3
- package/dist/collection/UserIcon.d.ts +0 -12
- package/dist/collection/UserIcon.js +0 -19
- package/dist/spa/icon/Icon.registry.js +0 -4
package/README.md
CHANGED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
## Vite: только используемые SPA-иконки в dist
|
|
4
|
+
|
|
5
|
+
Для SPA рекомендуется подключить compile-time plugin:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
// vite.config.ts
|
|
9
|
+
import react from "@vitejs/plugin-react"
|
|
10
|
+
import { defineConfig } from "vite"
|
|
11
|
+
import { dubiumIcons } from "@dubium/icons/vite"
|
|
12
|
+
|
|
13
|
+
export default defineConfig({
|
|
14
|
+
plugins: [
|
|
15
|
+
dubiumIcons(),
|
|
16
|
+
react(),
|
|
17
|
+
],
|
|
18
|
+
})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
После этого API остаётся прежним:
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { Icon } from "@dubium/icons/spa"
|
|
25
|
+
|
|
26
|
+
export const Header = () => (
|
|
27
|
+
<>
|
|
28
|
+
<Icon name="User" />
|
|
29
|
+
<Icon name="Search" />
|
|
30
|
+
</>
|
|
31
|
+
)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`@dubium/icons/vite` заранее сканирует `src`, создаёт virtual registry и генерирует
|
|
35
|
+
только такие lazy imports:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
{
|
|
39
|
+
User: () => import("@dubium/icons/icons/User"),
|
|
40
|
+
Search: () => import("@dubium/icons/icons/Search"),
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Поэтому остальные иконки из npm-пакета не попадают в `dist` consuming-приложения.
|
|
45
|
+
|
|
46
|
+
### Динамический name
|
|
47
|
+
|
|
48
|
+
Значение вида `<Icon name={item.icon} />` невозможно определить на этапе сборки.
|
|
49
|
+
Перечислите допустимые runtime-иконки вручную:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
dubiumIcons({
|
|
53
|
+
include: ["User", "Search", "Settings"],
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
По умолчанию плагин предупреждает о динамических `name`. Чтобы делать это ошибкой сборки:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
dubiumIcons({
|
|
61
|
+
include: ["User", "Search"],
|
|
62
|
+
strictDynamicNames: true,
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
По умолчанию сканируется каталог `src`. Для монорепозитория или другой структуры:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
dubiumIcons({
|
|
70
|
+
scan: ["src", "app", "../shared/src"],
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## Lightweight 5-icon test build
|
|
77
|
+
|
|
78
|
+
This archive intentionally keeps only the first five source SVG files so local testing stays fast:
|
|
79
|
+
|
|
80
|
+
- `123.svg` → `Icon123Icon`
|
|
81
|
+
- `24-hours.svg` → `Icon24HoursIcon`
|
|
82
|
+
- `2fa.svg` → `Icon2faIcon`
|
|
83
|
+
- `360-view.svg` → `Icon360ViewIcon`
|
|
84
|
+
- `360.svg` → `Icon360Icon`
|
|
85
|
+
|
|
86
|
+
Bundler-friendly container usage:
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { Icon } from "@dubium/icons/container"
|
|
90
|
+
import { Icon360Icon } from "@dubium/icons/icons/Icon360Icon"
|
|
91
|
+
|
|
92
|
+
export function Example() {
|
|
93
|
+
return <Icon icon={Icon360Icon} size={24} />
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The older short subpath remains compatible too:
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import Icon360Icon from "@dubium/icons/icons/Icon360"
|
|
101
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
+
//#region src/icons/collection/Icon123Icon.tsx
|
|
3
|
+
var t = ({ color: t = "var(--icon-color, currentColor)", ...n }) => /* @__PURE__ */ e("svg", {
|
|
4
|
+
...n,
|
|
5
|
+
fill: "none",
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
7
|
+
width: "100%",
|
|
8
|
+
height: "100%",
|
|
9
|
+
children: /* @__PURE__ */ e("path", {
|
|
10
|
+
stroke: t,
|
|
11
|
+
strokeLinecap: "round",
|
|
12
|
+
strokeLinejoin: "round",
|
|
13
|
+
strokeWidth: "2",
|
|
14
|
+
d: "m3 10 2-2v8m4-8h3a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h3m4-8h2.5A1.5 1.5 0 0 1 21 9.5v1a1.5 1.5 0 0 1-1.5 1.5m0 0H18m1.5 0a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5H17"
|
|
15
|
+
})
|
|
16
|
+
});
|
|
17
|
+
//#endregion
|
|
18
|
+
export { t as Icon123Icon, t as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
+
//#region src/icons/collection/Icon24HoursIcon.tsx
|
|
3
|
+
var t = ({ color: t = "var(--icon-color, currentColor)", ...n }) => /* @__PURE__ */ e("svg", {
|
|
4
|
+
...n,
|
|
5
|
+
fill: "none",
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
7
|
+
width: "100%",
|
|
8
|
+
height: "100%",
|
|
9
|
+
children: /* @__PURE__ */ e("path", {
|
|
10
|
+
stroke: t,
|
|
11
|
+
strokeLinecap: "round",
|
|
12
|
+
strokeLinejoin: "round",
|
|
13
|
+
strokeWidth: "2",
|
|
14
|
+
d: "M20 11A8.1 8.1 0 0 0 4.5 9M4 5v4h4m-4 4a8 8 0 0 0 3 5.24M11 15h2a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1h-1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h2m3-6v2a1 1 0 0 0 1 1h1m1-3v6"
|
|
15
|
+
})
|
|
16
|
+
});
|
|
17
|
+
//#endregion
|
|
18
|
+
export { t as Icon24HoursIcon, t as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
+
//#region src/icons/collection/Icon2faIcon.tsx
|
|
3
|
+
var t = ({ color: t = "var(--icon-color, currentColor)", ...n }) => /* @__PURE__ */ e("svg", {
|
|
4
|
+
...n,
|
|
5
|
+
fill: "none",
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
7
|
+
width: "100%",
|
|
8
|
+
height: "100%",
|
|
9
|
+
children: /* @__PURE__ */ e("path", {
|
|
10
|
+
stroke: t,
|
|
11
|
+
strokeLinecap: "round",
|
|
12
|
+
strokeLinejoin: "round",
|
|
13
|
+
strokeWidth: "2",
|
|
14
|
+
d: "M7 16H3l3.47-4.66A2 2 0 1 0 3 9.8m7 6.2V8h4m-4 4h3m4 4v-6a2 2 0 1 1 4 0v6m-4-3h4"
|
|
15
|
+
})
|
|
16
|
+
});
|
|
17
|
+
//#endregion
|
|
18
|
+
export { t as Icon2faIcon, t as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
+
//#region src/icons/collection/Icon360Icon.tsx
|
|
3
|
+
var t = ({ color: t = "var(--icon-color, currentColor)", ...n }) => /* @__PURE__ */ e("svg", {
|
|
4
|
+
...n,
|
|
5
|
+
fill: "none",
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
7
|
+
width: "100%",
|
|
8
|
+
height: "100%",
|
|
9
|
+
children: /* @__PURE__ */ e("path", {
|
|
10
|
+
stroke: t,
|
|
11
|
+
strokeLinecap: "round",
|
|
12
|
+
strokeLinejoin: "round",
|
|
13
|
+
strokeWidth: "2",
|
|
14
|
+
d: "M17 15.33c2.41-.72 4-1.94 4-3.33 0-2.21-4.03-4-9-4s-9 1.79-9 4 4.03 4 9 4m-3 3 3-3-3-3"
|
|
15
|
+
})
|
|
16
|
+
});
|
|
17
|
+
//#endregion
|
|
18
|
+
export { t as Icon360Icon, t as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
+
//#region src/icons/collection/Icon360ViewIcon.tsx
|
|
3
|
+
var t = ({ color: t = "var(--icon-color, currentColor)", ...n }) => /* @__PURE__ */ e("svg", {
|
|
4
|
+
...n,
|
|
5
|
+
fill: "none",
|
|
6
|
+
viewBox: "0 0 24 24",
|
|
7
|
+
width: "100%",
|
|
8
|
+
height: "100%",
|
|
9
|
+
children: /* @__PURE__ */ e("path", {
|
|
10
|
+
stroke: t,
|
|
11
|
+
strokeLinecap: "round",
|
|
12
|
+
strokeLinejoin: "round",
|
|
13
|
+
strokeWidth: "2",
|
|
14
|
+
d: "M14 6a1 1 0 0 0-1-1h-2a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1h-3M3 5h2.5A1.5 1.5 0 0 1 7 6.5v1A1.5 1.5 0 0 1 5.5 9m0 0H4m1.5 0A1.5 1.5 0 0 1 7 10.5v1A1.5 1.5 0 0 1 5.5 13H3m0 3c0 1.66 4.03 3 9 3s9-1.34 9-3m-4-9v4a2 2 0 0 0 4 0V7a2 2 0 1 0-4 0"
|
|
15
|
+
})
|
|
16
|
+
});
|
|
17
|
+
//#endregion
|
|
18
|
+
export { t as Icon360ViewIcon, t as default };
|
|
@@ -3,4 +3,8 @@
|
|
|
3
3
|
* Do not edit manually.
|
|
4
4
|
*/
|
|
5
5
|
export type { IIconComponentProps } from "./types.js";
|
|
6
|
-
export { default as
|
|
6
|
+
export { default as Icon123Icon } from "./Icon123Icon.js";
|
|
7
|
+
export { default as Icon24HoursIcon } from "./Icon24HoursIcon.js";
|
|
8
|
+
export { default as Icon2faIcon } from "./Icon2faIcon.js";
|
|
9
|
+
export { default as Icon360Icon } from "./Icon360Icon.js";
|
|
10
|
+
export { default as Icon360ViewIcon } from "./Icon360ViewIcon.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Icon123Icon as e } from "./Icon123Icon.js";
|
|
2
|
+
import { Icon24HoursIcon as t } from "./Icon24HoursIcon.js";
|
|
3
|
+
import { Icon2faIcon as n } from "./Icon2faIcon.js";
|
|
4
|
+
import { Icon360Icon as r } from "./Icon360Icon.js";
|
|
5
|
+
import { Icon360ViewIcon as i } from "./Icon360ViewIcon.js";
|
|
6
|
+
export { e as Icon123Icon, t as Icon24HoursIcon, n as Icon2faIcon, r as Icon360Icon, i as Icon360ViewIcon };
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import type { SVGProps } from "react";
|
|
2
|
-
/**
|
|
3
|
-
* Базовые пропсы для SVG-иконки.
|
|
4
|
-
*
|
|
5
|
-
* Расширяет стандартные SVG-атрибуты и добавляет поддержку цвета.
|
|
6
|
-
*
|
|
7
|
-
* @property color - Цвет заливки иконки (обычно прокидывается в `fill`)
|
|
8
|
-
*/
|
|
2
|
+
/** Props shared by generated SVG icon components. */
|
|
9
3
|
export interface IIconComponentProps extends SVGProps<SVGSVGElement> {
|
|
10
4
|
color?: string;
|
|
5
|
+
secondaryColor?: string;
|
|
11
6
|
}
|
package/dist/spa/icon/Icon.d.ts
CHANGED
|
@@ -1,57 +1,25 @@
|
|
|
1
1
|
import { type MemoExoticComponent } from "react";
|
|
2
2
|
import type { TEmptyIconRegistry, TIconName, TIconRegistry } from "./Icon.types.js";
|
|
3
|
-
/**
|
|
4
|
-
* Свойства компонента иконки
|
|
5
|
-
*/
|
|
6
3
|
export interface IconProps<TCustomIcons extends TIconRegistry = TEmptyIconRegistry> {
|
|
7
|
-
/**
|
|
8
|
-
* Атрибут aria-label
|
|
9
|
-
*/
|
|
10
4
|
ariaLabel?: string;
|
|
11
|
-
/**
|
|
12
|
-
* Цвет иконки
|
|
13
|
-
*/
|
|
14
5
|
color?: string;
|
|
15
|
-
|
|
16
|
-
* Угол поворота
|
|
17
|
-
*/
|
|
6
|
+
secondaryColor?: string;
|
|
18
7
|
deg?: number;
|
|
19
|
-
/**
|
|
20
|
-
* Высота (если нужен прямоугольник)
|
|
21
|
-
*/
|
|
22
8
|
height?: number;
|
|
23
|
-
/**
|
|
24
|
-
* Имя иконки
|
|
25
|
-
*/
|
|
26
9
|
name: TIconName<TCustomIcons>;
|
|
27
|
-
/**
|
|
28
|
-
* Обработчик клика
|
|
29
|
-
*/
|
|
30
10
|
onClick?: VoidFunction;
|
|
31
|
-
/**
|
|
32
|
-
* Приоритетный размер (квадратный)
|
|
33
|
-
*/
|
|
34
11
|
size?: number;
|
|
35
|
-
/**
|
|
36
|
-
* Ширина (если нужен прямоугольник)
|
|
37
|
-
*/
|
|
38
12
|
width?: number;
|
|
39
13
|
}
|
|
40
14
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* @param props - Свойства компонента иконки
|
|
44
|
-
* @param props.name - Имя иконки для отображения
|
|
45
|
-
* @param props.size - Размер иконки в пикселях (по умолчанию 24)
|
|
46
|
-
* @param props.color - Цвет иконки (по умолчанию "currentColor")
|
|
47
|
-
* @param props.deg - Угол поворота иконки в градусах (по умолчанию 0)
|
|
48
|
-
* @param props.onClick - Обработчик клика по иконке
|
|
15
|
+
* SPA-иконка с lazy loading.
|
|
49
16
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
17
|
+
* Встроенные loader-ы поступают из virtual:@dubium/icons-registry.
|
|
18
|
+
* Этот virtual module создаёт @dubium/icons/vite на этапе сборки приложения
|
|
19
|
+
* и помещает в него только статически используемые <Icon name="..." />.
|
|
52
20
|
*
|
|
53
|
-
*
|
|
21
|
+
* Пользовательский IconProvider имеет приоритет над встроенным registry.
|
|
54
22
|
*/
|
|
55
|
-
declare const IconComponentBase: <TCustomIcons extends TIconRegistry = TEmptyIconRegistry>({ name, size, width: propWidth, height: propHeight, color, deg, onClick: handleOnClick, ariaLabel, }: IconProps<TCustomIcons>) => import("react").JSX.Element;
|
|
23
|
+
declare const IconComponentBase: <TCustomIcons extends TIconRegistry = TEmptyIconRegistry>({ name, size, width: propWidth, height: propHeight, color, secondaryColor, deg, onClick: handleOnClick, ariaLabel, }: IconProps<TCustomIcons>) => import("react").JSX.Element;
|
|
56
24
|
declare const MemoizedIcon: MemoExoticComponent<typeof IconComponentBase> & typeof IconComponentBase;
|
|
57
25
|
export { MemoizedIcon as Icon };
|
package/dist/spa/icon/Icon.js
CHANGED
|
@@ -1,62 +1,56 @@
|
|
|
1
1
|
import { useIconContext as e } from "../provider/IconProvider.context.js";
|
|
2
|
-
import {
|
|
2
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
3
3
|
import { memo as n, useEffect as r, useMemo as i, useState as a } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { iconRegistry as o } from "virtual:@dubium/icons-registry";
|
|
5
5
|
//#region src/icons/spa/icon/Icon.tsx
|
|
6
|
-
var s = /* @__PURE__ */ new Map(), c = n(({ name: n, size: c = 24, width: l, height: u, color: d = "currentColor",
|
|
7
|
-
let { icons:
|
|
8
|
-
...t,
|
|
9
|
-
...h
|
|
10
|
-
}), [h]), _ = g[n], [v, y] = a(() => _ ? s.get(_) ?? null : null), [b, x] = a(!1), S = l ?? c, C = u ?? c, w = i(() => ({
|
|
11
|
-
display: "inline-flex",
|
|
6
|
+
var s = /* @__PURE__ */ new Map(), c = n(({ name: n, size: c = 24, width: l, height: u, color: d = "var(--icon-color, currentColor)", secondaryColor: f = "var(--icon-secondary-color, currentColor)", deg: p = 0, onClick: m, ariaLabel: h }) => {
|
|
7
|
+
let { icons: g } = e(), _ = g[n] ?? o[String(n)], [v, y] = a(() => _ ? s.get(_) ?? null : null), [b, x] = a(!1), S = l ?? c, C = u ?? c, w = i(() => ({
|
|
12
8
|
alignItems: "center",
|
|
13
|
-
|
|
14
|
-
width: S,
|
|
9
|
+
display: "inline-flex",
|
|
15
10
|
height: C,
|
|
16
|
-
|
|
11
|
+
justifyContent: "center",
|
|
12
|
+
transform: `rotate(${p}deg)`,
|
|
13
|
+
width: S
|
|
17
14
|
}), [
|
|
18
|
-
S,
|
|
19
15
|
C,
|
|
20
|
-
|
|
16
|
+
S,
|
|
17
|
+
p
|
|
21
18
|
]);
|
|
22
19
|
return r(() => {
|
|
23
|
-
let e = !1;
|
|
24
|
-
return (
|
|
25
|
-
let t = String(n), r = g[n];
|
|
26
|
-
if (!r) {
|
|
27
|
-
console.warn(`Иконка "${t}" не найдена`), y(() => null);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
let i = s.get(r);
|
|
31
|
-
if (i) {
|
|
32
|
-
y(() => i);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
x(!0), y(() => null), r().then((t) => {
|
|
36
|
-
if (e) return;
|
|
37
|
-
let n = t.default;
|
|
38
|
-
s.set(r, n), y(() => n);
|
|
39
|
-
}).catch((n) => {
|
|
40
|
-
e || (console.error(`Ошибка загрузки иконки "${t}":`, n), y(() => null));
|
|
41
|
-
}).finally(() => {
|
|
42
|
-
e || x(!1);
|
|
43
|
-
});
|
|
44
|
-
})(), () => {
|
|
20
|
+
let e = !1, t = String(n), r = g[n] ?? o[t];
|
|
21
|
+
if (!r) return x(!1), y(null), console.warn(`Иконка "${t}" не найдена в compile-time registry. Для динамического name добавьте её в dubiumIcons({ include: ["..."] }).`), () => {
|
|
45
22
|
e = !0;
|
|
46
23
|
};
|
|
47
|
-
|
|
24
|
+
let i = s.get(r);
|
|
25
|
+
return i ? (x(!1), y(() => i), () => {
|
|
26
|
+
e = !0;
|
|
27
|
+
}) : (x(!0), y(null), r().then((t) => {
|
|
28
|
+
if (e) return;
|
|
29
|
+
let n = t.default;
|
|
30
|
+
s.set(r, n), y(() => n);
|
|
31
|
+
}).catch((n) => {
|
|
32
|
+
e || (console.error(`Ошибка загрузки иконки "${t}":`, n), y(null));
|
|
33
|
+
}).finally(() => {
|
|
34
|
+
e || x(!1);
|
|
35
|
+
}), () => {
|
|
36
|
+
e = !0;
|
|
37
|
+
});
|
|
38
|
+
}, [g, n]), b || !v ? /* @__PURE__ */ t("div", {
|
|
48
39
|
"aria-hidden": "true",
|
|
49
40
|
role: "img",
|
|
50
41
|
style: {
|
|
51
42
|
...w,
|
|
52
43
|
visibility: "hidden"
|
|
53
44
|
}
|
|
54
|
-
}) : /* @__PURE__ */
|
|
55
|
-
"aria-label":
|
|
56
|
-
onClick:
|
|
45
|
+
}) : /* @__PURE__ */ t("div", {
|
|
46
|
+
"aria-label": h || String(n),
|
|
47
|
+
onClick: m,
|
|
57
48
|
role: "img",
|
|
58
49
|
style: w,
|
|
59
|
-
children:
|
|
50
|
+
children: /* @__PURE__ */ t(v, {
|
|
51
|
+
color: d,
|
|
52
|
+
secondaryColor: f
|
|
53
|
+
})
|
|
60
54
|
});
|
|
61
55
|
});
|
|
62
56
|
c.displayName = "Icon";
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AUTO-GENERATED by scripts/sync-icons.mjs.
|
|
3
|
-
* Source of truth:
|
|
3
|
+
* Source of truth: icons/source/*.svg.
|
|
4
4
|
*/
|
|
5
5
|
export declare const defaultIcons: {
|
|
6
|
-
readonly
|
|
6
|
+
readonly Icon123: () => Promise<typeof import("../../collection/Icon123Icon.js")>;
|
|
7
|
+
readonly Icon24Hours: () => Promise<typeof import("../../collection/Icon24HoursIcon.js")>;
|
|
8
|
+
readonly Icon2fa: () => Promise<typeof import("../../collection/Icon2faIcon.js")>;
|
|
9
|
+
readonly Icon360: () => Promise<typeof import("../../collection/Icon360Icon.js")>;
|
|
10
|
+
readonly Icon360View: () => Promise<typeof import("../../collection/Icon360ViewIcon.js")>;
|
|
7
11
|
};
|
|
8
12
|
export type TDefaultIconName = keyof typeof defaultIcons;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { IconContext as e } from "./IconProvider.context.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo as n } from "react";
|
|
4
4
|
//#region src/icons/spa/provider/IconProvider.tsx
|
|
5
5
|
var r = ({ children: r, icons: i }) => {
|
|
6
|
-
let a =
|
|
7
|
-
return /* @__PURE__ */
|
|
6
|
+
let a = n(() => ({ icons: i ?? {} }), [i]);
|
|
7
|
+
return /* @__PURE__ */ t(e.Provider, {
|
|
8
8
|
value: a,
|
|
9
9
|
children: r
|
|
10
10
|
});
|
package/dist/ssr/icon/Icon.js
CHANGED
|
@@ -7,20 +7,21 @@ var r = (e, t) => Object.prototype.hasOwnProperty.call(e, t), i = async (t) => {
|
|
|
7
7
|
let n = e[t];
|
|
8
8
|
return (await n()).default;
|
|
9
9
|
}, a = async (e, a) => {
|
|
10
|
-
let { name: o, size: s = 24, width: c, height: l, color: u = "currentColor",
|
|
11
|
-
return
|
|
12
|
-
ariaLabel:
|
|
13
|
-
deg:
|
|
10
|
+
let { name: o, size: s = 24, width: c, height: l, color: u = "var(--icon-color, currentColor)", secondaryColor: d = "var(--icon-secondary-color, currentColor)", deg: f = 0, ariaLabel: p, style: m } = e, h = String(o), g = (a && r(a, h) ? a[h] : void 0) ?? await i(h);
|
|
11
|
+
return g ? /* @__PURE__ */ n(t, {
|
|
12
|
+
ariaLabel: p,
|
|
13
|
+
deg: f,
|
|
14
14
|
height: l,
|
|
15
15
|
size: s,
|
|
16
|
-
style:
|
|
16
|
+
style: m,
|
|
17
17
|
width: c,
|
|
18
|
-
children: /* @__PURE__ */ n(
|
|
18
|
+
children: /* @__PURE__ */ n(g, {
|
|
19
19
|
"aria-hidden": "true",
|
|
20
20
|
color: u,
|
|
21
|
-
focusable: "false"
|
|
21
|
+
focusable: "false",
|
|
22
|
+
secondaryColor: d
|
|
22
23
|
})
|
|
23
|
-
}) : (console.warn(`Иконка "${
|
|
24
|
+
}) : (console.warn(`Иконка "${h}" не найдена`), null);
|
|
24
25
|
}, o = (e) => a(e), s = a;
|
|
25
26
|
//#endregion
|
|
26
27
|
export { o as Icon, s as renderIconWithRegistry };
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AUTO-GENERATED by scripts/sync-icons.mjs.
|
|
3
|
-
* Source of truth:
|
|
3
|
+
* Source of truth: icons/source/*.svg.
|
|
4
4
|
*/
|
|
5
5
|
export declare const defaultIcons: {
|
|
6
|
-
readonly
|
|
6
|
+
readonly Icon123: () => Promise<typeof import("../../collection/Icon123Icon.js")>;
|
|
7
|
+
readonly Icon24Hours: () => Promise<typeof import("../../collection/Icon24HoursIcon.js")>;
|
|
8
|
+
readonly Icon2fa: () => Promise<typeof import("../../collection/Icon2faIcon.js")>;
|
|
9
|
+
readonly Icon360: () => Promise<typeof import("../../collection/Icon360Icon.js")>;
|
|
10
|
+
readonly Icon360View: () => Promise<typeof import("../../collection/Icon360ViewIcon.js")>;
|
|
7
11
|
};
|
|
8
12
|
export type TDefaultIconName = keyof typeof defaultIcons;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
//#region src/icons/ssr/icon/Icon.registry.ts
|
|
2
|
-
var e = {
|
|
2
|
+
var e = {
|
|
3
|
+
Icon123: () => import("../../collection/Icon123Icon.js"),
|
|
4
|
+
Icon24Hours: () => import("../../collection/Icon24HoursIcon.js"),
|
|
5
|
+
Icon2fa: () => import("../../collection/Icon2faIcon.js"),
|
|
6
|
+
Icon360: () => import("../../collection/Icon360Icon.js"),
|
|
7
|
+
Icon360View: () => import("../../collection/Icon360ViewIcon.js")
|
|
8
|
+
};
|
|
3
9
|
//#endregion
|
|
4
10
|
export { e as defaultIcons };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
export interface DubiumIconsPluginOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Имена компонентов, которые плагин должен анализировать.
|
|
5
|
+
*
|
|
6
|
+
* @default ["Icon"]
|
|
7
|
+
*/
|
|
8
|
+
componentNames?: readonly string[];
|
|
9
|
+
/**
|
|
10
|
+
* Иконки, которые необходимо включить вручную.
|
|
11
|
+
*
|
|
12
|
+
* Используется для runtime-имён:
|
|
13
|
+
* `<Icon name={valueFromApi} />`.
|
|
14
|
+
*/
|
|
15
|
+
include?: readonly string[];
|
|
16
|
+
/**
|
|
17
|
+
* Имя npm-пакета с иконками.
|
|
18
|
+
*
|
|
19
|
+
* @default "@dubium/icons"
|
|
20
|
+
*/
|
|
21
|
+
packageName?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Каталоги приложения, которые нужно сканировать.
|
|
24
|
+
* Пути могут быть абсолютными или относительными к Vite root.
|
|
25
|
+
*
|
|
26
|
+
* @default ["src"]
|
|
27
|
+
*/
|
|
28
|
+
scan?: readonly string[];
|
|
29
|
+
/**
|
|
30
|
+
* Если true, сборка завершится ошибкой при обнаружении
|
|
31
|
+
* `<Icon name={dynamicValue} />`.
|
|
32
|
+
*
|
|
33
|
+
* При false будет выведено предупреждение.
|
|
34
|
+
*
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
strictDynamicNames?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Vite-плагин для compile-time извлечения используемых иконок.
|
|
41
|
+
*
|
|
42
|
+
* Он сканирует JSX/TSX, находит статические:
|
|
43
|
+
* `<Icon name="User" />`,
|
|
44
|
+
* а затем создаёт virtual registry только для найденных имён.
|
|
45
|
+
*
|
|
46
|
+
* Благодаря этому Rollup/Vite видит dynamic import() только реально
|
|
47
|
+
* используемых иконок, и остальные иконки не попадают в dist приложения.
|
|
48
|
+
*/
|
|
49
|
+
export declare const dubiumIcons: (options?: DubiumIconsPluginOptions) => Plugin;
|
|
50
|
+
export default dubiumIcons;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { readFile as e, readdir as t } from "node:fs/promises";
|
|
2
|
+
import { extname as n, isAbsolute as r, join as i, relative as a, resolve as o } from "node:path";
|
|
3
|
+
//#region src/icons/vite/index.ts
|
|
4
|
+
var s = "virtual:@dubium/icons-registry", c = `\0${s}`, l = /* @__PURE__ */ new Set([
|
|
5
|
+
".js",
|
|
6
|
+
".jsx",
|
|
7
|
+
".mjs",
|
|
8
|
+
".cjs",
|
|
9
|
+
".ts",
|
|
10
|
+
".tsx"
|
|
11
|
+
]), u = /* @__PURE__ */ new Set([
|
|
12
|
+
".git",
|
|
13
|
+
".next",
|
|
14
|
+
".nuxt",
|
|
15
|
+
".output",
|
|
16
|
+
".turbo",
|
|
17
|
+
"build",
|
|
18
|
+
"coverage",
|
|
19
|
+
"dist",
|
|
20
|
+
"node_modules"
|
|
21
|
+
]), d = (e) => e.replaceAll("\\", "/"), f = (e, t) => {
|
|
22
|
+
if (e.size !== t.size) return !1;
|
|
23
|
+
for (let n of e) if (!t.has(n)) return !1;
|
|
24
|
+
return !0;
|
|
25
|
+
}, p = (e) => {
|
|
26
|
+
let t = e.map((e) => e.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"));
|
|
27
|
+
return RegExp(`<\\s*(?:${t.join("|")})\\b`, "gu");
|
|
28
|
+
}, m = (e, t) => {
|
|
29
|
+
let n = null, r = !1, i = 0;
|
|
30
|
+
for (let a = t; a < e.length; a += 1) {
|
|
31
|
+
let t = e[a];
|
|
32
|
+
if (n) {
|
|
33
|
+
if (r) {
|
|
34
|
+
r = !1;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (t === "\\") {
|
|
38
|
+
r = !0;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
t === n && (n = null);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (t === "'" || t === "\"" || t === "`") {
|
|
45
|
+
n = t;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (t === "{") {
|
|
49
|
+
i += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (t === "}") {
|
|
53
|
+
i = Math.max(0, i - 1);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (t === ">" && i === 0) return a;
|
|
57
|
+
}
|
|
58
|
+
return -1;
|
|
59
|
+
}, h = (e) => {
|
|
60
|
+
let t = /\bname\s*=\s*(["'])(.*?)\1/su.exec(e);
|
|
61
|
+
if (t) return t[2].trim();
|
|
62
|
+
let n = /\bname\s*=\s*\{\s*(?:(["'])(.*?)\1|`([^`${}]*)`)\s*\}/su.exec(e);
|
|
63
|
+
return n ? (n[2] ?? n[3] ?? "").trim() : null;
|
|
64
|
+
}, g = (e) => /\bname\s*=/u.test(e), _ = (e, t) => {
|
|
65
|
+
let n = /* @__PURE__ */ new Set(), r = p(t), i = 0;
|
|
66
|
+
for (let t of e.matchAll(r)) {
|
|
67
|
+
let r = t.index ?? 0, a = m(e, r);
|
|
68
|
+
if (a === -1) continue;
|
|
69
|
+
let o = e.slice(r, a + 1), s = h(o);
|
|
70
|
+
if (s) {
|
|
71
|
+
n.add(s);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
g(o) && (i += 1);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
dynamicNames: i,
|
|
78
|
+
icons: n
|
|
79
|
+
};
|
|
80
|
+
}, v = async (e) => {
|
|
81
|
+
let r;
|
|
82
|
+
try {
|
|
83
|
+
r = await t(e, { withFileTypes: !0 });
|
|
84
|
+
} catch {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
let a = [];
|
|
88
|
+
for (let t of r) {
|
|
89
|
+
let r = i(e, t.name);
|
|
90
|
+
if (t.isDirectory()) {
|
|
91
|
+
u.has(t.name) || a.push(...await v(r));
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
t.isFile() && l.has(n(t.name).toLowerCase()) && a.push(r);
|
|
95
|
+
}
|
|
96
|
+
return a;
|
|
97
|
+
}, y = (e, t) => `/**
|
|
98
|
+
* AUTO-GENERATED in memory by @dubium/icons/vite.
|
|
99
|
+
* Contains only icons used by the current application.
|
|
100
|
+
*/
|
|
101
|
+
export const iconRegistry = {
|
|
102
|
+
${e.map((e) => `\t${JSON.stringify(e)}: () => import(${JSON.stringify(`${t}/icons/${e}`)}),`).join("\n")}
|
|
103
|
+
}
|
|
104
|
+
`, b = (t = {}) => {
|
|
105
|
+
let i = t.componentNames?.length ? [...t.componentNames] : ["Icon"], u = t.packageName ?? "@dubium/icons", p = t.scan?.length ? [...t.scan] : ["src"], m = new Set(t.include ?? []), h = /* @__PURE__ */ new Map(), g = /* @__PURE__ */ new Map(), b = process.cwd(), x, S = () => {
|
|
106
|
+
let e = new Set(m);
|
|
107
|
+
for (let t of h.values()) for (let n of t) e.add(n);
|
|
108
|
+
return [...e].sort((e, t) => e.localeCompare(t));
|
|
109
|
+
}, C = async (t) => {
|
|
110
|
+
let r = d(t);
|
|
111
|
+
if (!l.has(n(t).toLowerCase())) return h.delete(r), g.delete(r), !1;
|
|
112
|
+
let a;
|
|
113
|
+
try {
|
|
114
|
+
a = await e(t, "utf8");
|
|
115
|
+
} catch {
|
|
116
|
+
let e = h.delete(r), t = g.delete(r);
|
|
117
|
+
return e || t;
|
|
118
|
+
}
|
|
119
|
+
let o = h.get(r) ?? /* @__PURE__ */ new Set(), s = g.get(r) ?? 0, c = _(a, i);
|
|
120
|
+
return h.set(r, c.icons), c.dynamicNames > 0 ? g.set(r, c.dynamicNames) : g.delete(r), !f(o, c.icons) || s !== c.dynamicNames;
|
|
121
|
+
}, w = async (e) => {
|
|
122
|
+
h.clear(), g.clear();
|
|
123
|
+
for (let t of p) {
|
|
124
|
+
let n = await v(r(t) ? t : o(b, t));
|
|
125
|
+
for (let t of n) e?.addWatchFile(t), await C(t);
|
|
126
|
+
}
|
|
127
|
+
}, T = () => g.size === 0 ? null : `[@dubium/icons] Найдены динамические name у <Icon>:\n${[...g.entries()].map(([e, t]) => ` - ${d(a(b, e))}: ${t}`).join("\n")}\nVite не может определить такие иконки на этапе сборки. Добавьте допустимые имена в dubiumIcons({ include: [...] }).`, E = () => {
|
|
128
|
+
if (!x) return;
|
|
129
|
+
let e = x.moduleGraph.getModuleById(c);
|
|
130
|
+
e && x.moduleGraph.invalidateModule(e), x.ws.send({ type: "full-reload" });
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
name: "dubium-icons",
|
|
134
|
+
enforce: "pre",
|
|
135
|
+
configResolved(e) {
|
|
136
|
+
b = e.root;
|
|
137
|
+
},
|
|
138
|
+
async buildStart() {
|
|
139
|
+
await w(this);
|
|
140
|
+
let e = T();
|
|
141
|
+
e && (t.strictDynamicNames ? this.error(e) : this.warn(e));
|
|
142
|
+
},
|
|
143
|
+
configureServer(e) {
|
|
144
|
+
x = e;
|
|
145
|
+
let t = async (e) => {
|
|
146
|
+
await C(e) && E();
|
|
147
|
+
}, n = async (e) => {
|
|
148
|
+
let t = d(e);
|
|
149
|
+
(h.delete(t) || g.delete(t)) && E();
|
|
150
|
+
};
|
|
151
|
+
return e.watcher.on("add", t), e.watcher.on("unlink", n), () => {
|
|
152
|
+
e.watcher.off("add", t), e.watcher.off("unlink", n);
|
|
153
|
+
};
|
|
154
|
+
},
|
|
155
|
+
resolveId(e) {
|
|
156
|
+
return e === s ? c : null;
|
|
157
|
+
},
|
|
158
|
+
load(e) {
|
|
159
|
+
return e === c ? y(S(), u) : null;
|
|
160
|
+
},
|
|
161
|
+
async handleHotUpdate(e) {
|
|
162
|
+
if (await C(e.file)) return E(), [];
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
//#endregion
|
|
167
|
+
export { b as default, b as dubiumIcons };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dubium/icons",
|
|
3
|
-
"version": "0.0.2-alpha.
|
|
3
|
+
"version": "0.0.2-alpha.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -20,20 +20,31 @@
|
|
|
20
20
|
"types": "./dist/collection/index.d.ts",
|
|
21
21
|
"import": "./dist/collection/index.js"
|
|
22
22
|
},
|
|
23
|
+
"./icons/*Icon": {
|
|
24
|
+
"types": "./dist/collection/*Icon.d.ts",
|
|
25
|
+
"import": "./dist/collection/*Icon.js"
|
|
26
|
+
},
|
|
23
27
|
"./icons/*": {
|
|
24
28
|
"types": "./dist/collection/*Icon.d.ts",
|
|
25
29
|
"import": "./dist/collection/*Icon.js"
|
|
30
|
+
},
|
|
31
|
+
"./vite": {
|
|
32
|
+
"types": "./dist/vite/index.d.ts",
|
|
33
|
+
"import": "./dist/vite/index.js"
|
|
26
34
|
}
|
|
27
35
|
},
|
|
28
36
|
"scripts": {
|
|
29
37
|
"dev": "vite",
|
|
30
38
|
"build": "vite build && tsc -p tsconfig.build.json",
|
|
39
|
+
"build:icons": "vite build --config vite.icons.config.ts",
|
|
40
|
+
"sync:icons": "node scripts/sync-icons.mjs",
|
|
31
41
|
"lint": "oxlint",
|
|
32
42
|
"lint:fix": "oxlint --fix",
|
|
33
43
|
"format": "oxfmt",
|
|
34
44
|
"format:check": "oxfmt --check",
|
|
35
45
|
"check": "npm run lint && npm run format:check && npm run typecheck",
|
|
36
|
-
"preview": "vite preview"
|
|
46
|
+
"preview": "vite preview",
|
|
47
|
+
"typecheck": "tsc --noEmit"
|
|
37
48
|
},
|
|
38
49
|
"devDependencies": {
|
|
39
50
|
"@types/node": "^24.13.3",
|
|
@@ -44,11 +55,18 @@
|
|
|
44
55
|
"oxlint": "^1.78.0",
|
|
45
56
|
"oxlint-tsgolint": "^7.0.2001",
|
|
46
57
|
"rollup-plugin-visualizer": "^7.0.1",
|
|
58
|
+
"svgo": "^4.0.2",
|
|
47
59
|
"typescript": "~7.0.2",
|
|
48
60
|
"vite": "^8.2.1"
|
|
49
61
|
},
|
|
50
62
|
"peerDependencies": {
|
|
51
63
|
"react": "^18.0.0 || ^19.0.0",
|
|
52
|
-
"react-dom": "^18.0.0 || ^19.0.0"
|
|
64
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
65
|
+
"vite": "^8.0.0"
|
|
66
|
+
},
|
|
67
|
+
"peerDependenciesMeta": {
|
|
68
|
+
"vite": {
|
|
69
|
+
"optional": true
|
|
70
|
+
}
|
|
53
71
|
}
|
|
54
72
|
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { IIconComponentProps } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
* Иконка.
|
|
4
|
-
*
|
|
5
|
-
* @remarks
|
|
6
|
-
* свойство `color` из {@link IIconComponentProps}.
|
|
7
|
-
*
|
|
8
|
-
* @param props - Свойства компонента иконки.
|
|
9
|
-
* @returns SVG-элемент иконки.
|
|
10
|
-
*/
|
|
11
|
-
declare const UserIcon: ({ color, ...props }: IIconComponentProps) => import("react").JSX.Element;
|
|
12
|
-
export default UserIcon;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
-
//#region src/icons/collection/UserIcon.tsx
|
|
3
|
-
var t = ({ color: t = "currentColor", ...n }) => /* @__PURE__ */ e("svg", {
|
|
4
|
-
fill: "none",
|
|
5
|
-
height: "100%",
|
|
6
|
-
viewBox: "0 0 24 24",
|
|
7
|
-
width: "100%",
|
|
8
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
9
|
-
...n,
|
|
10
|
-
children: /* @__PURE__ */ e("path", {
|
|
11
|
-
d: "M6 21V19C6 17.9391 6.42143 16.9217 7.17157 16.1716C7.92172 15.4214 8.93913 15 10 15H14C15.0609 15 16.0783 15.4214 16.8284 16.1716C17.5786 16.9217 18 17.9391 18 19V21M8 7C8 8.06087 8.42143 9.07828 9.17157 9.82843C9.92172 10.5786 10.9391 11 12 11C13.0609 11 14.0783 10.5786 14.8284 9.82843C15.5786 9.07828 16 8.06087 16 7C16 5.93913 15.5786 4.92172 14.8284 4.17157C14.0783 3.42143 13.0609 3 12 3C10.9391 3 9.92172 3.42143 9.17157 4.17157C8.42143 4.92172 8 5.93913 8 7Z",
|
|
12
|
-
stroke: t,
|
|
13
|
-
strokeLinecap: "round",
|
|
14
|
-
strokeLinejoin: "round",
|
|
15
|
-
strokeWidth: "2"
|
|
16
|
-
})
|
|
17
|
-
});
|
|
18
|
-
//#endregion
|
|
19
|
-
export { t as default };
|