@iobroker/gui-components 10.3.13 → 10.3.15
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 +11 -1
- package/build/Components/AnimatedIcons/IconBell.d.ts +21 -0
- package/build/Components/AnimatedIcons/IconBell.js +50 -0
- package/build/Components/AnimatedIcons/IconBell.js.map +1 -0
- package/build/Components/AnimatedIcons/IconConnectionState.d.ts +19 -0
- package/build/Components/AnimatedIcons/IconConnectionState.js +25 -0
- package/build/Components/AnimatedIcons/IconConnectionState.js.map +1 -0
- package/build/Components/AnimatedIcons/IconExpertMode.d.ts +22 -0
- package/build/Components/AnimatedIcons/IconExpertMode.js +47 -0
- package/build/Components/AnimatedIcons/IconExpertMode.js.map +1 -0
- package/build/Components/AnimatedIcons/IconFolder.d.ts +22 -0
- package/build/Components/AnimatedIcons/IconFolder.js +29 -0
- package/build/Components/AnimatedIcons/IconFolder.js.map +1 -0
- package/build/Components/AnimatedIcons/IconMenuArrow.d.ts +23 -0
- package/build/Components/AnimatedIcons/IconMenuArrow.js +26 -0
- package/build/Components/AnimatedIcons/IconMenuArrow.js.map +1 -0
- package/build/Components/AnimatedIcons/IconPlayPause.d.ts +23 -0
- package/build/Components/AnimatedIcons/IconPlayPause.js +25 -0
- package/build/Components/AnimatedIcons/IconPlayPause.js.map +1 -0
- package/build/Components/AnimatedIcons/IconRefresh.d.ts +23 -0
- package/build/Components/AnimatedIcons/IconRefresh.js +86 -0
- package/build/Components/AnimatedIcons/IconRefresh.js.map +1 -0
- package/build/Components/AnimatedIcons/IconResult.d.ts +21 -0
- package/build/Components/AnimatedIcons/IconResult.js +36 -0
- package/build/Components/AnimatedIcons/IconResult.js.map +1 -0
- package/build/Components/AnimatedIcons/IconStatusLed.d.ts +25 -0
- package/build/Components/AnimatedIcons/IconStatusLed.js +58 -0
- package/build/Components/AnimatedIcons/IconStatusLed.js.map +1 -0
- package/build/Components/AnimatedIcons/IconTrash.d.ts +20 -0
- package/build/Components/AnimatedIcons/IconTrash.js +23 -0
- package/build/Components/AnimatedIcons/IconTrash.js.map +1 -0
- package/build/Components/AnimatedIcons/common.d.ts +31 -0
- package/build/Components/AnimatedIcons/common.js +164 -0
- package/build/Components/AnimatedIcons/common.js.map +1 -0
- package/build/Components/DeviceType/DeviceTypeIcon.js +2 -1
- package/build/Components/DeviceType/DeviceTypeIcon.js.map +1 -1
- package/build/Components/DeviceType/i18n/de.json +1 -0
- package/build/Components/DeviceType/i18n/en.json +1 -0
- package/build/Components/DeviceType/i18n/es.json +1 -0
- package/build/Components/DeviceType/i18n/fr.json +1 -0
- package/build/Components/DeviceType/i18n/it.json +1 -0
- package/build/Components/DeviceType/i18n/nl.json +1 -0
- package/build/Components/DeviceType/i18n/pl.json +1 -0
- package/build/Components/DeviceType/i18n/pt.json +1 -0
- package/build/Components/DeviceType/i18n/ru.json +1 -0
- package/build/Components/DeviceType/i18n/uk.json +1 -0
- package/build/Components/DeviceType/i18n/zh-cn.json +1 -0
- package/build/Components/FileBrowser.js +4 -5
- package/build/Components/FileBrowser.js.map +1 -1
- package/build/Components/Loaders/Community.d.ts +13 -2
- package/build/Components/Loaders/Community.js +176 -243
- package/build/Components/Loaders/Community.js.map +1 -1
- package/build/Components/Loaders/CommunityLegacy.d.ts +32 -0
- package/build/Components/Loaders/CommunityLegacy.js +266 -0
- package/build/Components/Loaders/CommunityLegacy.js.map +1 -0
- package/build/Components/ObjectBrowser/ObjectBrowserClass.d.ts +9 -0
- package/build/Components/ObjectBrowser/ObjectBrowserClass.js +62 -2
- package/build/Components/ObjectBrowser/ObjectBrowserClass.js.map +1 -1
- package/build/Components/ObjectBrowser/dialogs.js +2 -2
- package/build/Components/ObjectBrowser/dialogs.js.map +1 -1
- package/build/Components/ObjectBrowser/renderLeaf.js +6 -6
- package/build/Components/ObjectBrowser/renderLeaf.js.map +1 -1
- package/build/Components/ObjectBrowser/rowAnimation.d.ts +9 -0
- package/build/Components/ObjectBrowser/rowAnimation.js +122 -0
- package/build/Components/ObjectBrowser/rowAnimation.js.map +1 -0
- package/build/Components/ObjectBrowser/toolbar.js +5 -4
- package/build/Components/ObjectBrowser/toolbar.js.map +1 -1
- package/build/index.d.ts +13 -0
- package/build/index.js +12 -0
- package/build/index.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconResult.js","sourceRoot":"./src/","sources":["Components/AnimatedIcons/IconResult.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAA0B,SAAS,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AASpF;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC7C,qBAAqB,EAAE,CAAC;IACxB,IAAI,IAAuB,CAAC;IAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,GAAG,CACH,8BACI,SAAS,EAAC,kBAAkB,EAC5B,CAAC,EAAC,qBAAqB,EACvB,UAAU,EAAE,CAAC,GACf,CACL,CAAC;IACN,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAClC,IAAI,GAAG,CACH;YACI,8BACI,SAAS,EAAC,kBAAkB,EAC5B,CAAC,EAAC,WAAW,EACb,UAAU,EAAE,CAAC,GACf;YACF,8BACI,SAAS,EAAC,mBAAmB,EAC7B,CAAC,EAAC,aAAa,EACf,UAAU,EAAE,CAAC,GACf,CACH,CACN,CAAC;IACN,CAAC;SAAM,CAAC;QACJ,IAAI,GAAG,CACH;YACI,8BACI,SAAS,EAAC,kBAAkB,EAC5B,CAAC,EAAC,kBAAkB,EACpB,UAAU,EAAE,CAAC,GACf;YACF,8BACI,SAAS,EAAC,mBAAmB,EAC7B,CAAC,EAAC,oBAAoB,EACtB,UAAU,EAAE,CAAC,GACf,CACH,CACN,CAAC;IACN,CAAC;IAED,OAAO,CACH,iCAAU,SAAS,CAAC,KAAK,EAAE,2BAA2B,KAAK,CAAC,IAAI,EAAE,CAAC;QAC/D,6BACI,GAAG,EAAE,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,IAAI,EAAE,EAAE,EAC1C,OAAO,EAAC,WAAW;YAEnB,gCACI,SAAS,EAAC,oBAAoB,EAC9B,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAC,IAAI,EACN,UAAU,EAAE,CAAC,GACf;YACD,IAAI,CACH,CACH,CACV,CAAC;AACN,CAAC","sourcesContent":["/**\n * Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>\n *\n * MIT License\n */\nimport React from 'react';\nimport { type AnimatedIconProps, rootProps, useAnimatedIconStyles } from './common';\n\nexport interface IconResultProps extends AnimatedIconProps {\n /** success: check mark (green), warning: exclamation mark (orange), error: cross (red). The color can be changed with `style.color`. */\n type: 'success' | 'warning' | 'error';\n /** Every change of this value draws the icon again, e.g. a counter of the save clicks */\n replay?: string | number;\n}\n\n/**\n * Result of an action: a circle and the mark draw themselves, a warning or an error shakes once.\n *\n * ```tsx\n * {saved ? <IconResult type=\"success\" replay={saveCount} /> : null}\n * ```\n */\nexport function IconResult(props: IconResultProps): React.JSX.Element {\n useAnimatedIconStyles();\n let mark: React.JSX.Element;\n if (props.type === 'success') {\n mark = (\n <path\n className=\"iob-ani-res-mark\"\n d=\"M7.5 12.5l3 3 6-6.5\"\n pathLength={1}\n />\n );\n } else if (props.type === 'warning') {\n mark = (\n <>\n <path\n className=\"iob-ani-res-mark\"\n d=\"M12 7.5v5\"\n pathLength={1}\n />\n <path\n className=\"iob-ani-res-mark2\"\n d=\"M12 16.4v.1\"\n pathLength={1}\n />\n </>\n );\n } else {\n mark = (\n <>\n <path\n className=\"iob-ani-res-mark\"\n d=\"M8.7 8.7l6.6 6.6\"\n pathLength={1}\n />\n <path\n className=\"iob-ani-res-mark2\"\n d=\"M15.3 8.7l-6.6 6.6\"\n pathLength={1}\n />\n </>\n );\n }\n\n return (\n <span {...rootProps(props, `iob-ani-res iob-ani-res-${props.type}`)}>\n <svg\n key={`${props.type}-${props.replay ?? ''}`}\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"iob-ani-res-circle\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n pathLength={1}\n />\n {mark}\n </svg>\n </span>\n );\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { type AnimatedIconProps } from './common';
|
|
8
|
+
export interface IconStatusLedProps extends AnimatedIconProps {
|
|
9
|
+
/** 'green', 'orange', 'yellow', 'red', 'blue', 'grey' or any CSS color */
|
|
10
|
+
color: string;
|
|
11
|
+
/** Every change of this value sends one pulse, e.g. the timestamp of the last `alive` update */
|
|
12
|
+
beat?: string | number | boolean | null;
|
|
13
|
+
/** Waiting, e.g. while the instance starts: the LED breathes */
|
|
14
|
+
blink?: boolean;
|
|
15
|
+
/** Own status symbol instead of the round LED. Pulse, pop and shake stay, the pulse has the size of the icon. */
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Status LED. It pops when its color changes, shakes when it turns red and sends a pulse on every `beat`.
|
|
20
|
+
*
|
|
21
|
+
* ```tsx
|
|
22
|
+
* <IconStatusLed color={alive ? 'green' : 'red'} beat={aliveState?.ts} />
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function IconStatusLed(props: IconStatusLedProps): React.JSX.Element;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*/
|
|
6
|
+
import React, { useRef } from 'react';
|
|
7
|
+
import { play, rootProps, useAnimatedIconStyles, useChange } from './common';
|
|
8
|
+
/** Colors of the named states; any other CSS color can be given too */
|
|
9
|
+
const COLORS = {
|
|
10
|
+
green: '#4CAF50',
|
|
11
|
+
orange: '#FF9800',
|
|
12
|
+
yellow: '#FFC107',
|
|
13
|
+
red: '#F44336',
|
|
14
|
+
blue: '#2196F3',
|
|
15
|
+
grey: '#9E9E9E',
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Status LED. It pops when its color changes, shakes when it turns red and sends a pulse on every `beat`.
|
|
19
|
+
*
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <IconStatusLed color={alive ? 'green' : 'red'} beat={aliveState?.ts} />
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function IconStatusLed(props) {
|
|
25
|
+
useAnimatedIconStyles();
|
|
26
|
+
const root = useRef(null);
|
|
27
|
+
const dot = useRef(null);
|
|
28
|
+
const ping = useRef(null);
|
|
29
|
+
const color = COLORS[props.color] || props.color;
|
|
30
|
+
useChange(props.beat, () => play(ping.current, [
|
|
31
|
+
{ transform: 'scale(1)', opacity: 0.55 },
|
|
32
|
+
// an own symbol fills the icon, its pulse grows less
|
|
33
|
+
{ transform: `scale(${props.children ? 1.7 : 2.3})`, opacity: 0 },
|
|
34
|
+
], { duration: 750, easing: 'cubic-bezier(0, 0, 0.2, 1)' }));
|
|
35
|
+
useChange(color, () => {
|
|
36
|
+
if (color === COLORS.red) {
|
|
37
|
+
play(root.current, [
|
|
38
|
+
{ transform: 'translateX(0)' },
|
|
39
|
+
{ transform: 'translateX(-0.09em)' },
|
|
40
|
+
{ transform: 'translateX(0.09em)' },
|
|
41
|
+
{ transform: 'translateX(-0.06em)' },
|
|
42
|
+
{ transform: 'translateX(0.06em)' },
|
|
43
|
+
{ transform: 'translateX(0)' },
|
|
44
|
+
], { duration: 450, easing: 'ease-in-out' });
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
play(dot.current, [{ transform: 'scale(0.55)' }, { transform: 'scale(1.25)' }, { transform: 'scale(1)' }], {
|
|
48
|
+
duration: 380,
|
|
49
|
+
easing: 'ease-out',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
const ledProps = rootProps(props, `iob-ani-led${props.blink ? ' iob-ani-led-blink' : ''}`);
|
|
54
|
+
return (React.createElement("span", { ...ledProps, ref: root, style: { ...ledProps.style, '--iob-ani-led': color } },
|
|
55
|
+
React.createElement("span", { className: props.children ? 'iob-ani-led-ping iob-ani-led-full' : 'iob-ani-led-ping', ref: ping }),
|
|
56
|
+
props.children ? (React.createElement("span", { className: "iob-ani-layer iob-ani-led-own", ref: dot }, props.children)) : (React.createElement("span", { className: "iob-ani-led-dot", ref: dot }))));
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=IconStatusLed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconStatusLed.js","sourceRoot":"./src/","sources":["Components/AnimatedIcons/IconStatusLed.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>\n *\n * MIT License\n */\nimport React, { useRef, type CSSProperties } from 'react';\nimport { type AnimatedIconProps, play, rootProps, useAnimatedIconStyles, useChange } from './common';\n\n/** Colors of the named states; any other CSS color can be given too */\nconst COLORS: Record<string, string> = {\n green: '#4CAF50',\n orange: '#FF9800',\n yellow: '#FFC107',\n red: '#F44336',\n blue: '#2196F3',\n grey: '#9E9E9E',\n};\n\nexport interface IconStatusLedProps extends AnimatedIconProps {\n /** 'green', 'orange', 'yellow', 'red', 'blue', 'grey' or any CSS color */\n color: string;\n /** Every change of this value sends one pulse, e.g. the timestamp of the last `alive` update */\n beat?: string | number | boolean | null;\n /** Waiting, e.g. while the instance starts: the LED breathes */\n blink?: boolean;\n /** Own status symbol instead of the round LED. Pulse, pop and shake stay, the pulse has the size of the icon. */\n children?: React.ReactNode;\n}\n\n/**\n * Status LED. It pops when its color changes, shakes when it turns red and sends a pulse on every `beat`.\n *\n * ```tsx\n * <IconStatusLed color={alive ? 'green' : 'red'} beat={aliveState?.ts} />\n * ```\n */\nexport function IconStatusLed(props: IconStatusLedProps): React.JSX.Element {\n useAnimatedIconStyles();\n const root = useRef<HTMLSpanElement>(null);\n const dot = useRef<HTMLSpanElement>(null);\n const ping = useRef<HTMLSpanElement>(null);\n const color = COLORS[props.color] || props.color;\n\n useChange(props.beat, () =>\n play(\n ping.current,\n [\n { transform: 'scale(1)', opacity: 0.55 },\n // an own symbol fills the icon, its pulse grows less\n { transform: `scale(${props.children ? 1.7 : 2.3})`, opacity: 0 },\n ],\n { duration: 750, easing: 'cubic-bezier(0, 0, 0.2, 1)' },\n ),\n );\n\n useChange(color, () => {\n if (color === COLORS.red) {\n play(\n root.current,\n [\n { transform: 'translateX(0)' },\n { transform: 'translateX(-0.09em)' },\n { transform: 'translateX(0.09em)' },\n { transform: 'translateX(-0.06em)' },\n { transform: 'translateX(0.06em)' },\n { transform: 'translateX(0)' },\n ],\n { duration: 450, easing: 'ease-in-out' },\n );\n } else {\n play(dot.current, [{ transform: 'scale(0.55)' }, { transform: 'scale(1.25)' }, { transform: 'scale(1)' }], {\n duration: 380,\n easing: 'ease-out',\n });\n }\n });\n\n const ledProps = rootProps(props, `iob-ani-led${props.blink ? ' iob-ani-led-blink' : ''}`);\n return (\n <span\n {...ledProps}\n ref={root}\n style={{ ...ledProps.style, '--iob-ani-led': color } as CSSProperties}\n >\n <span\n className={props.children ? 'iob-ani-led-ping iob-ani-led-full' : 'iob-ani-led-ping'}\n ref={ping}\n />\n {props.children ? (\n <span\n className=\"iob-ani-layer iob-ani-led-own\"\n ref={dot}\n >\n {props.children}\n </span>\n ) : (\n <span\n className=\"iob-ani-led-dot\"\n ref={dot}\n />\n )}\n </span>\n );\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { type AnimatedIconProps } from './common';
|
|
8
|
+
export interface IconTrashProps extends AnimatedIconProps {
|
|
9
|
+
/** Keeps the lid open, e.g. while a delete confirmation is shown */
|
|
10
|
+
open?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Trash can for delete buttons. The lid opens when the mouse is over the icon or over the button around it
|
|
14
|
+
* (`IconButton`, the start icon of a `Button`, a link...), or when that button has the keyboard focus.
|
|
15
|
+
*
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <IconButton onClick={...}><IconTrash /></IconButton>
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function IconTrash(props: IconTrashProps): React.JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { rootProps, useAnimatedIconStyles } from './common';
|
|
8
|
+
/**
|
|
9
|
+
* Trash can for delete buttons. The lid opens when the mouse is over the icon or over the button around it
|
|
10
|
+
* (`IconButton`, the start icon of a `Button`, a link...), or when that button has the keyboard focus.
|
|
11
|
+
*
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <IconButton onClick={...}><IconTrash /></IconButton>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function IconTrash(props) {
|
|
17
|
+
useAnimatedIconStyles();
|
|
18
|
+
return (React.createElement("span", { ...rootProps(props, `iob-ani-trash${props.open ? ' iob-ani-trash-open' : ''}`) },
|
|
19
|
+
React.createElement("svg", { viewBox: "0 0 24 24" },
|
|
20
|
+
React.createElement("path", { className: "iob-ani-trash-lid", fill: "currentColor", d: "M19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" }),
|
|
21
|
+
React.createElement("path", { fill: "currentColor", d: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12z" }))));
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=IconTrash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconTrash.js","sourceRoot":"./src/","sources":["Components/AnimatedIcons/IconTrash.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAA0B,SAAS,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAOpF;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,KAAqB;IAC3C,qBAAqB,EAAE,CAAC;IACxB,OAAO,CACH,iCAAU,SAAS,CAAC,KAAK,EAAE,gBAAgB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACjF,6BAAK,OAAO,EAAC,WAAW;YACpB,8BACI,SAAS,EAAC,mBAAmB,EAC7B,IAAI,EAAC,cAAc,EACnB,CAAC,EAAC,mCAAmC,GACvC;YACF,8BACI,IAAI,EAAC,cAAc,EACnB,CAAC,EAAC,8CAA8C,GAClD,CACA,CACH,CACV,CAAC;AACN,CAAC","sourcesContent":["/**\n * Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>\n *\n * MIT License\n */\nimport React from 'react';\nimport { type AnimatedIconProps, rootProps, useAnimatedIconStyles } from './common';\n\nexport interface IconTrashProps extends AnimatedIconProps {\n /** Keeps the lid open, e.g. while a delete confirmation is shown */\n open?: boolean;\n}\n\n/**\n * Trash can for delete buttons. The lid opens when the mouse is over the icon or over the button around it\n * (`IconButton`, the start icon of a `Button`, a link...), or when that button has the keyboard focus.\n *\n * ```tsx\n * <IconButton onClick={...}><IconTrash /></IconButton>\n * ```\n */\nexport function IconTrash(props: IconTrashProps): React.JSX.Element {\n useAnimatedIconStyles();\n return (\n <span {...rootProps(props, `iob-ani-trash${props.open ? ' iob-ani-trash-open' : ''}`)}>\n <svg viewBox=\"0 0 24 24\">\n <path\n className=\"iob-ani-trash-lid\"\n fill=\"currentColor\"\n d=\"M19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z\"\n />\n <path\n fill=\"currentColor\"\n d=\"M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12z\"\n />\n </svg>\n </span>\n );\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Shared parts of the animated icons: props, size, the style sheet and helpers.
|
|
7
|
+
* The icons are plain CSS/SVG (no animation library). They use `currentColor`, so they take the color of the
|
|
8
|
+
* surrounding text or button, and they have the size of the MUI icons.
|
|
9
|
+
*/
|
|
10
|
+
import type React from 'react';
|
|
11
|
+
import { type CSSProperties } from 'react';
|
|
12
|
+
export interface AnimatedIconProps {
|
|
13
|
+
/** Size like the MUI icons: 'small' (20 px), 'medium' (24 px, default), 'large' (35 px), 'inherit', pixels or e.g. '2em' */
|
|
14
|
+
fontSize?: 'inherit' | 'small' | 'medium' | 'large' | number | `${number}${'px' | 'em' | 'rem' | '%'}`;
|
|
15
|
+
/** Class name for the root element */
|
|
16
|
+
className?: string;
|
|
17
|
+
/** Styles for the root element, e.g. `color` */
|
|
18
|
+
style?: CSSProperties;
|
|
19
|
+
/** Accessible name. Without it, the icon is decorative and hidden from screen readers. */
|
|
20
|
+
ariaLabel?: string;
|
|
21
|
+
}
|
|
22
|
+
/** Puts the style sheet of the animated icons into the page, once and before the first paint */
|
|
23
|
+
export declare function useAnimatedIconStyles(): void;
|
|
24
|
+
/** Properties of the root element: class, size and accessibility */
|
|
25
|
+
export declare function rootProps(props: AnimatedIconProps, className: string): React.HTMLAttributes<HTMLSpanElement>;
|
|
26
|
+
/** True if the user asked the system for less motion */
|
|
27
|
+
export declare function prefersReducedMotion(): boolean;
|
|
28
|
+
/** Plays a one-time animation (Web Animations API), unless the user wants less motion */
|
|
29
|
+
export declare function play(element: Element | null | undefined, keyframes: Keyframe[], options: KeyframeAnimationOptions): Animation | null;
|
|
30
|
+
/** Calls `onChange` when `value` changes, but not on the first render */
|
|
31
|
+
export declare function useChange<T>(value: T, onChange: (value: T, previous: T) => void): void;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { useEffect, useInsertionEffect, useRef } from 'react';
|
|
2
|
+
const SIZES = {
|
|
3
|
+
small: '1.25rem',
|
|
4
|
+
medium: '1.5rem',
|
|
5
|
+
large: '2.1875rem',
|
|
6
|
+
inherit: 'inherit',
|
|
7
|
+
};
|
|
8
|
+
const STYLE_ID = 'iob-animated-icons';
|
|
9
|
+
const styles = `
|
|
10
|
+
/* zero specificity: MUI may set the size, e.g. 20 px for the start icon of a Button, like for its own icons */
|
|
11
|
+
:where(.iob-ani) { font-size: 1.5rem; }
|
|
12
|
+
.iob-ani { display: inline-block; position: relative; width: 1em; height: 1em; flex-shrink: 0; vertical-align: middle; line-height: 0; user-select: none; }
|
|
13
|
+
.iob-ani > svg, .iob-ani-layer { position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: visible; }
|
|
14
|
+
|
|
15
|
+
/* Play / pause: two halves of the triangle become the two bars */
|
|
16
|
+
.iob-ani-pp-a, .iob-ani-pp-b { position: absolute; inset: 0; background: currentColor; transition: clip-path 0.32s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s ease; }
|
|
17
|
+
.iob-ani-pp-a { clip-path: polygon(33.33% 20.83%, 56.25% 35.42%, 56.25% 64.58%, 33.33% 79.17%); }
|
|
18
|
+
.iob-ani-pp-b { clip-path: polygon(56.25% 35.42%, 79.17% 50%, 79.17% 50%, 56.25% 64.58%); }
|
|
19
|
+
.iob-ani-on .iob-ani-pp-a { clip-path: polygon(25% 20.83%, 41.67% 20.83%, 41.67% 79.17%, 25% 79.17%); }
|
|
20
|
+
.iob-ani-on .iob-ani-pp-b { clip-path: polygon(58.33% 20.83%, 75% 20.83%, 75% 79.17%, 58.33% 79.17%); }
|
|
21
|
+
.iob-ani-pp-ring { opacity: 0; transition: opacity 0.2s; }
|
|
22
|
+
.iob-ani-pp-ring circle { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-dasharray: 0.22 0.78; }
|
|
23
|
+
.iob-ani-pp-pending .iob-ani-pp-ring { opacity: 1; animation: iob-ani-spin 0.9s linear infinite; }
|
|
24
|
+
.iob-ani-pp-pending .iob-ani-pp-a, .iob-ani-pp-pending .iob-ani-pp-b { transform: scale(0.72); }
|
|
25
|
+
|
|
26
|
+
/* Status LED */
|
|
27
|
+
.iob-ani-led-dot, .iob-ani-led-ping { position: absolute; left: 20%; top: 20%; width: 60%; height: 60%; border-radius: 50%; background-color: var(--iob-ani-led); }
|
|
28
|
+
.iob-ani-led-dot { transition: background-color 0.3s; box-shadow: inset 0 -0.05em 0.1em rgba(0, 0, 0, 0.28); }
|
|
29
|
+
.iob-ani-led-ping { opacity: 0; }
|
|
30
|
+
.iob-ani-led-blink .iob-ani-led-dot, .iob-ani-led-blink .iob-ani-led-own { animation: iob-ani-breathe 1.6s ease-in-out infinite; }
|
|
31
|
+
.iob-ani-led-ping.iob-ani-led-full { left: 0; top: 0; width: 100%; height: 100%; }
|
|
32
|
+
.iob-ani-led-own { display: flex; align-items: center; justify-content: center; line-height: normal; }
|
|
33
|
+
|
|
34
|
+
/* Result: circle and mark draw themselves */
|
|
35
|
+
:where(.iob-ani-res-success) { color: #4CAF50; }
|
|
36
|
+
:where(.iob-ani-res-warning) { color: #FF9800; }
|
|
37
|
+
:where(.iob-ani-res-error) { color: #F44336; }
|
|
38
|
+
.iob-ani-res svg * { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1 1; stroke-dashoffset: 1; }
|
|
39
|
+
.iob-ani-res-circle { transform: rotate(-90deg); transform-origin: 12px 12px; animation: iob-ani-draw 0.45s cubic-bezier(0.65, 0, 0.35, 1) forwards; }
|
|
40
|
+
.iob-ani-res-mark { animation: iob-ani-draw 0.3s cubic-bezier(0.65, 0, 0.35, 1) 0.35s forwards; }
|
|
41
|
+
.iob-ani-res-mark2 { animation: iob-ani-draw 0.3s cubic-bezier(0.65, 0, 0.35, 1) 0.5s forwards; }
|
|
42
|
+
.iob-ani-res-error svg, .iob-ani-res-warning svg { animation: iob-ani-shake 0.4s 0.75s; }
|
|
43
|
+
|
|
44
|
+
/* Refresh */
|
|
45
|
+
.iob-ani-rf-done { opacity: 0; }
|
|
46
|
+
.iob-ani-rf-done path { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1 1; stroke-dashoffset: 1; }
|
|
47
|
+
|
|
48
|
+
/* Bell */
|
|
49
|
+
.iob-ani-bell-body { transform-origin: 12px 3px; }
|
|
50
|
+
|
|
51
|
+
/* Menu / arrow: three bars, the icon turns by 180 degrees */
|
|
52
|
+
.iob-ani-menu-rot { transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1); }
|
|
53
|
+
.iob-ani-menu-open .iob-ani-menu-rot { transform: rotate(180deg); }
|
|
54
|
+
.iob-ani-menu-right .iob-ani-menu-flip { transform: scaleX(-1); }
|
|
55
|
+
.iob-ani-menu-bar { position: absolute; left: 0.125em; width: 0.75em; height: 0.0834em; margin-top: -0.0417em; border-radius: 0.02em; background: currentColor; transform-origin: 100% 50%; transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1); }
|
|
56
|
+
.iob-ani-menu-b1 { top: 0.2917em; }
|
|
57
|
+
.iob-ani-menu-b2 { top: 0.5em; }
|
|
58
|
+
.iob-ani-menu-b3 { top: 0.7083em; }
|
|
59
|
+
.iob-ani-menu-open .iob-ani-menu-b1 { transform: translate(-0.0417em, 0.2083em) rotate(45deg) scaleX(0.63); }
|
|
60
|
+
.iob-ani-menu-open .iob-ani-menu-b2 { transform: translateX(-0.0417em) scaleX(0.889); }
|
|
61
|
+
.iob-ani-menu-open .iob-ani-menu-b3 { transform: translate(-0.0417em, -0.2083em) rotate(-45deg) scaleX(0.63); }
|
|
62
|
+
|
|
63
|
+
/* Trash: the lid opens on hover of the icon or of its button */
|
|
64
|
+
.iob-ani-trash-lid { transform-origin: 5px 6px; transition: transform 0.25s cubic-bezier(0.3, 1.5, 0.6, 1); }
|
|
65
|
+
.iob-ani-trash-open .iob-ani-trash-lid,
|
|
66
|
+
.iob-ani-trash:hover .iob-ani-trash-lid,
|
|
67
|
+
:is(button, a, [role="button"]):hover .iob-ani-trash .iob-ani-trash-lid,
|
|
68
|
+
:is(button, a, [role="button"]):focus-visible .iob-ani-trash .iob-ani-trash-lid { transform: translateY(-1.5px) rotate(-18deg); }
|
|
69
|
+
|
|
70
|
+
/* Expert mode: mortarboard, outlined when off and filled when on */
|
|
71
|
+
.iob-ani-expert-hat { transform-origin: 12px 12px; }
|
|
72
|
+
.iob-ani-expert-shape { fill: currentColor; fill-opacity: 0; stroke: currentColor; stroke-width: 1.6; stroke-linejoin: round; transition: fill-opacity 0.18s ease; }
|
|
73
|
+
.iob-ani-expert-on .iob-ani-expert-shape { fill-opacity: 1; transition-delay: 0.12s; }
|
|
74
|
+
.iob-ani-expert-tassel { transform-origin: 21.2px 9.1px; }
|
|
75
|
+
.iob-ani-expert-cord { fill: none; stroke: currentColor; stroke-width: 1.3; stroke-linecap: round; }
|
|
76
|
+
.iob-ani-expert-tuft { fill: currentColor; stroke: currentColor; stroke-width: 0.8; stroke-linejoin: round; }
|
|
77
|
+
|
|
78
|
+
/* Folder: closed, the front flap lies on the back like a closed folder; open, it folds down. The closed
|
|
79
|
+
shape covers both until the flap starts to move, so the closed folder looks exactly like IconClosed */
|
|
80
|
+
.iob-ani-folder path { fill: currentColor; }
|
|
81
|
+
.iob-ani-folder-front { transform-origin: 104px 448px; transform: scaleY(1.1667) skewX(29.1deg); transition: transform 0.22s cubic-bezier(0.4, 0, 0.2, 1); }
|
|
82
|
+
.iob-ani-folder-open .iob-ani-folder-front { transform: none; transition: transform 0.32s cubic-bezier(0.3, 1.35, 0.5, 1); }
|
|
83
|
+
.iob-ani-folder-closed { transition: opacity 0.06s linear 0.18s; }
|
|
84
|
+
.iob-ani-folder-open .iob-ani-folder-closed { opacity: 0; transition-delay: 0s; }
|
|
85
|
+
|
|
86
|
+
/* Connection */
|
|
87
|
+
.iob-ani-wifi path { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; transition: opacity 0.3s; }
|
|
88
|
+
.iob-ani-wifi circle { fill: currentColor; transition: opacity 0.3s; }
|
|
89
|
+
.iob-ani-wifi .iob-ani-wifi-slash { stroke-dasharray: 1 1; stroke-dashoffset: 1; transition: stroke-dashoffset 0.35s cubic-bezier(0.65, 0, 0.35, 1); }
|
|
90
|
+
.iob-ani-wifi-disconnected .iob-ani-wifi-slash { stroke-dashoffset: 0; }
|
|
91
|
+
.iob-ani-wifi-disconnected .iob-ani-wifi-w { opacity: 0.35; }
|
|
92
|
+
.iob-ani-wifi-connecting .iob-ani-wifi-w { animation: iob-ani-wave 1.5s ease-in-out infinite; }
|
|
93
|
+
.iob-ani-wifi-connecting .iob-ani-wifi-w1 { animation-delay: 0.18s; }
|
|
94
|
+
.iob-ani-wifi-connecting .iob-ani-wifi-w2 { animation-delay: 0.36s; }
|
|
95
|
+
.iob-ani-wifi-connecting .iob-ani-wifi-w3 { animation-delay: 0.54s; }
|
|
96
|
+
|
|
97
|
+
@keyframes iob-ani-spin { to { transform: rotate(360deg); } }
|
|
98
|
+
@keyframes iob-ani-draw { to { stroke-dashoffset: 0; } }
|
|
99
|
+
@keyframes iob-ani-breathe { 50% { opacity: 0.35; } }
|
|
100
|
+
@keyframes iob-ani-wave { 0%, 100% { opacity: 0.25; } 30% { opacity: 1; } }
|
|
101
|
+
@keyframes iob-ani-shake { 20% { transform: translateX(-1.5px); } 40% { transform: translateX(1.5px); } 60% { transform: translateX(-1px); } 80% { transform: translateX(1px); } }
|
|
102
|
+
|
|
103
|
+
@media (prefers-reduced-motion: reduce) {
|
|
104
|
+
.iob-ani-pp-a, .iob-ani-pp-b, .iob-ani-menu-rot, .iob-ani-menu-bar, .iob-ani-trash-lid, .iob-ani-expert-shape, .iob-ani-folder-front, .iob-ani-folder-closed { transition-duration: 0.01ms; transition-delay: 0s; }
|
|
105
|
+
.iob-ani-pp-pending .iob-ani-pp-ring { animation: iob-ani-breathe 1.2s ease-in-out infinite; }
|
|
106
|
+
.iob-ani-res svg, .iob-ani-res svg * { animation: none !important; stroke-dashoffset: 0; }
|
|
107
|
+
}
|
|
108
|
+
`;
|
|
109
|
+
/** Puts the style sheet of the animated icons into the page, once and before the first paint */
|
|
110
|
+
export function useAnimatedIconStyles() {
|
|
111
|
+
useInsertionEffect(() => {
|
|
112
|
+
if (!window.document.getElementById(STYLE_ID)) {
|
|
113
|
+
const style = window.document.createElement('style');
|
|
114
|
+
style.setAttribute('id', STYLE_ID);
|
|
115
|
+
style.innerHTML = styles;
|
|
116
|
+
window.document.head.appendChild(style);
|
|
117
|
+
}
|
|
118
|
+
}, []);
|
|
119
|
+
}
|
|
120
|
+
/** Properties of the root element: class, size and accessibility */
|
|
121
|
+
export function rootProps(props, className) {
|
|
122
|
+
// Without fontSize the size comes from the style sheet (24 px), so that MUI can change it like for its own icons
|
|
123
|
+
let fontSize;
|
|
124
|
+
if (typeof props.fontSize === 'number') {
|
|
125
|
+
fontSize = props.fontSize;
|
|
126
|
+
}
|
|
127
|
+
else if (props.fontSize) {
|
|
128
|
+
fontSize = SIZES[props.fontSize] || props.fontSize;
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
className: `iob-ani ${className}${props.className ? ` ${props.className}` : ''}`,
|
|
132
|
+
style: fontSize === undefined ? props.style : { fontSize, ...props.style },
|
|
133
|
+
role: props.ariaLabel ? 'img' : undefined,
|
|
134
|
+
'aria-label': props.ariaLabel,
|
|
135
|
+
'aria-hidden': props.ariaLabel ? undefined : true,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/** True if the user asked the system for less motion */
|
|
139
|
+
export function prefersReducedMotion() {
|
|
140
|
+
return !!window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
|
|
141
|
+
}
|
|
142
|
+
/** Plays a one-time animation (Web Animations API), unless the user wants less motion */
|
|
143
|
+
export function play(element, keyframes, options) {
|
|
144
|
+
if (!element?.animate || prefersReducedMotion()) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
return element.animate(keyframes, options);
|
|
148
|
+
}
|
|
149
|
+
/** Calls `onChange` when `value` changes, but not on the first render */
|
|
150
|
+
export function useChange(value, onChange) {
|
|
151
|
+
const previous = useRef(value);
|
|
152
|
+
const callback = useRef(onChange);
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
callback.current = onChange;
|
|
155
|
+
});
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
if (!Object.is(previous.current, value)) {
|
|
158
|
+
const old = previous.current;
|
|
159
|
+
previous.current = value;
|
|
160
|
+
callback.current(value, old);
|
|
161
|
+
}
|
|
162
|
+
}, [value]);
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=common.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"./src/","sources":["Components/AnimatedIcons/common.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAAsB,MAAM,OAAO,CAAC;AAalF,MAAM,KAAK,GAA2B;IAClC,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,WAAW;IAClB,OAAO,EAAE,SAAS;CACrB,CAAC;AAEF,MAAM,QAAQ,GAAG,oBAAoB,CAAC;AAEtC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmGd,CAAC;AAEF,gGAAgG;AAChG,MAAM,UAAU,qBAAqB;IACjC,kBAAkB,CAAC,GAAG,EAAE;QACpB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACrD,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACnC,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC;YACzB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5C,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;AACX,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,SAAS,CAAC,KAAwB,EAAE,SAAiB;IACjE,iHAAiH;IACjH,IAAI,QAAqC,CAAC;IAC1C,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACrC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC9B,CAAC;SAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACxB,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC;IACvD,CAAC;IACD,OAAO;QACH,SAAS,EAAE,WAAW,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;QAChF,KAAK,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE;QAC1E,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QACzC,YAAY,EAAE,KAAK,CAAC,SAAS;QAC7B,aAAa,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;KACpD,CAAC;AACN,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,oBAAoB;IAChC,OAAO,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,kCAAkC,CAAC,CAAC,OAAO,CAAC;AAC7E,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,IAAI,CAChB,OAAmC,EACnC,SAAqB,EACrB,OAAiC;IAEjC,IAAI,CAAC,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,EAAE,CAAC;QAC9C,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,SAAS,CAAI,KAAQ,EAAE,QAAyC;IAC5E,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAClC,SAAS,CAAC,GAAG,EAAE;QACX,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAC;IAChC,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;YACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC;YAC7B,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;YACzB,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;IACL,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AAChB,CAAC","sourcesContent":["/**\n * Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>\n *\n * MIT License\n *\n * Shared parts of the animated icons: props, size, the style sheet and helpers.\n * The icons are plain CSS/SVG (no animation library). They use `currentColor`, so they take the color of the\n * surrounding text or button, and they have the size of the MUI icons.\n */\nimport type React from 'react';\nimport { useEffect, useInsertionEffect, useRef, type CSSProperties } from 'react';\n\nexport interface AnimatedIconProps {\n /** Size like the MUI icons: 'small' (20 px), 'medium' (24 px, default), 'large' (35 px), 'inherit', pixels or e.g. '2em' */\n fontSize?: 'inherit' | 'small' | 'medium' | 'large' | number | `${number}${'px' | 'em' | 'rem' | '%'}`;\n /** Class name for the root element */\n className?: string;\n /** Styles for the root element, e.g. `color` */\n style?: CSSProperties;\n /** Accessible name. Without it, the icon is decorative and hidden from screen readers. */\n ariaLabel?: string;\n}\n\nconst SIZES: Record<string, string> = {\n small: '1.25rem',\n medium: '1.5rem',\n large: '2.1875rem',\n inherit: 'inherit',\n};\n\nconst STYLE_ID = 'iob-animated-icons';\n\nconst styles = `\n/* zero specificity: MUI may set the size, e.g. 20 px for the start icon of a Button, like for its own icons */\n:where(.iob-ani) { font-size: 1.5rem; }\n.iob-ani { display: inline-block; position: relative; width: 1em; height: 1em; flex-shrink: 0; vertical-align: middle; line-height: 0; user-select: none; }\n.iob-ani > svg, .iob-ani-layer { position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: visible; }\n\n/* Play / pause: two halves of the triangle become the two bars */\n.iob-ani-pp-a, .iob-ani-pp-b { position: absolute; inset: 0; background: currentColor; transition: clip-path 0.32s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s ease; }\n.iob-ani-pp-a { clip-path: polygon(33.33% 20.83%, 56.25% 35.42%, 56.25% 64.58%, 33.33% 79.17%); }\n.iob-ani-pp-b { clip-path: polygon(56.25% 35.42%, 79.17% 50%, 79.17% 50%, 56.25% 64.58%); }\n.iob-ani-on .iob-ani-pp-a { clip-path: polygon(25% 20.83%, 41.67% 20.83%, 41.67% 79.17%, 25% 79.17%); }\n.iob-ani-on .iob-ani-pp-b { clip-path: polygon(58.33% 20.83%, 75% 20.83%, 75% 79.17%, 58.33% 79.17%); }\n.iob-ani-pp-ring { opacity: 0; transition: opacity 0.2s; }\n.iob-ani-pp-ring circle { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-dasharray: 0.22 0.78; }\n.iob-ani-pp-pending .iob-ani-pp-ring { opacity: 1; animation: iob-ani-spin 0.9s linear infinite; }\n.iob-ani-pp-pending .iob-ani-pp-a, .iob-ani-pp-pending .iob-ani-pp-b { transform: scale(0.72); }\n\n/* Status LED */\n.iob-ani-led-dot, .iob-ani-led-ping { position: absolute; left: 20%; top: 20%; width: 60%; height: 60%; border-radius: 50%; background-color: var(--iob-ani-led); }\n.iob-ani-led-dot { transition: background-color 0.3s; box-shadow: inset 0 -0.05em 0.1em rgba(0, 0, 0, 0.28); }\n.iob-ani-led-ping { opacity: 0; }\n.iob-ani-led-blink .iob-ani-led-dot, .iob-ani-led-blink .iob-ani-led-own { animation: iob-ani-breathe 1.6s ease-in-out infinite; }\n.iob-ani-led-ping.iob-ani-led-full { left: 0; top: 0; width: 100%; height: 100%; }\n.iob-ani-led-own { display: flex; align-items: center; justify-content: center; line-height: normal; }\n\n/* Result: circle and mark draw themselves */\n:where(.iob-ani-res-success) { color: #4CAF50; }\n:where(.iob-ani-res-warning) { color: #FF9800; }\n:where(.iob-ani-res-error) { color: #F44336; }\n.iob-ani-res svg * { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1 1; stroke-dashoffset: 1; }\n.iob-ani-res-circle { transform: rotate(-90deg); transform-origin: 12px 12px; animation: iob-ani-draw 0.45s cubic-bezier(0.65, 0, 0.35, 1) forwards; }\n.iob-ani-res-mark { animation: iob-ani-draw 0.3s cubic-bezier(0.65, 0, 0.35, 1) 0.35s forwards; }\n.iob-ani-res-mark2 { animation: iob-ani-draw 0.3s cubic-bezier(0.65, 0, 0.35, 1) 0.5s forwards; }\n.iob-ani-res-error svg, .iob-ani-res-warning svg { animation: iob-ani-shake 0.4s 0.75s; }\n\n/* Refresh */\n.iob-ani-rf-done { opacity: 0; }\n.iob-ani-rf-done path { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1 1; stroke-dashoffset: 1; }\n\n/* Bell */\n.iob-ani-bell-body { transform-origin: 12px 3px; }\n\n/* Menu / arrow: three bars, the icon turns by 180 degrees */\n.iob-ani-menu-rot { transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1); }\n.iob-ani-menu-open .iob-ani-menu-rot { transform: rotate(180deg); }\n.iob-ani-menu-right .iob-ani-menu-flip { transform: scaleX(-1); }\n.iob-ani-menu-bar { position: absolute; left: 0.125em; width: 0.75em; height: 0.0834em; margin-top: -0.0417em; border-radius: 0.02em; background: currentColor; transform-origin: 100% 50%; transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1); }\n.iob-ani-menu-b1 { top: 0.2917em; }\n.iob-ani-menu-b2 { top: 0.5em; }\n.iob-ani-menu-b3 { top: 0.7083em; }\n.iob-ani-menu-open .iob-ani-menu-b1 { transform: translate(-0.0417em, 0.2083em) rotate(45deg) scaleX(0.63); }\n.iob-ani-menu-open .iob-ani-menu-b2 { transform: translateX(-0.0417em) scaleX(0.889); }\n.iob-ani-menu-open .iob-ani-menu-b3 { transform: translate(-0.0417em, -0.2083em) rotate(-45deg) scaleX(0.63); }\n\n/* Trash: the lid opens on hover of the icon or of its button */\n.iob-ani-trash-lid { transform-origin: 5px 6px; transition: transform 0.25s cubic-bezier(0.3, 1.5, 0.6, 1); }\n.iob-ani-trash-open .iob-ani-trash-lid,\n.iob-ani-trash:hover .iob-ani-trash-lid,\n:is(button, a, [role=\"button\"]):hover .iob-ani-trash .iob-ani-trash-lid,\n:is(button, a, [role=\"button\"]):focus-visible .iob-ani-trash .iob-ani-trash-lid { transform: translateY(-1.5px) rotate(-18deg); }\n\n/* Expert mode: mortarboard, outlined when off and filled when on */\n.iob-ani-expert-hat { transform-origin: 12px 12px; }\n.iob-ani-expert-shape { fill: currentColor; fill-opacity: 0; stroke: currentColor; stroke-width: 1.6; stroke-linejoin: round; transition: fill-opacity 0.18s ease; }\n.iob-ani-expert-on .iob-ani-expert-shape { fill-opacity: 1; transition-delay: 0.12s; }\n.iob-ani-expert-tassel { transform-origin: 21.2px 9.1px; }\n.iob-ani-expert-cord { fill: none; stroke: currentColor; stroke-width: 1.3; stroke-linecap: round; }\n.iob-ani-expert-tuft { fill: currentColor; stroke: currentColor; stroke-width: 0.8; stroke-linejoin: round; }\n\n/* Folder: closed, the front flap lies on the back like a closed folder; open, it folds down. The closed\n shape covers both until the flap starts to move, so the closed folder looks exactly like IconClosed */\n.iob-ani-folder path { fill: currentColor; }\n.iob-ani-folder-front { transform-origin: 104px 448px; transform: scaleY(1.1667) skewX(29.1deg); transition: transform 0.22s cubic-bezier(0.4, 0, 0.2, 1); }\n.iob-ani-folder-open .iob-ani-folder-front { transform: none; transition: transform 0.32s cubic-bezier(0.3, 1.35, 0.5, 1); }\n.iob-ani-folder-closed { transition: opacity 0.06s linear 0.18s; }\n.iob-ani-folder-open .iob-ani-folder-closed { opacity: 0; transition-delay: 0s; }\n\n/* Connection */\n.iob-ani-wifi path { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; transition: opacity 0.3s; }\n.iob-ani-wifi circle { fill: currentColor; transition: opacity 0.3s; }\n.iob-ani-wifi .iob-ani-wifi-slash { stroke-dasharray: 1 1; stroke-dashoffset: 1; transition: stroke-dashoffset 0.35s cubic-bezier(0.65, 0, 0.35, 1); }\n.iob-ani-wifi-disconnected .iob-ani-wifi-slash { stroke-dashoffset: 0; }\n.iob-ani-wifi-disconnected .iob-ani-wifi-w { opacity: 0.35; }\n.iob-ani-wifi-connecting .iob-ani-wifi-w { animation: iob-ani-wave 1.5s ease-in-out infinite; }\n.iob-ani-wifi-connecting .iob-ani-wifi-w1 { animation-delay: 0.18s; }\n.iob-ani-wifi-connecting .iob-ani-wifi-w2 { animation-delay: 0.36s; }\n.iob-ani-wifi-connecting .iob-ani-wifi-w3 { animation-delay: 0.54s; }\n\n@keyframes iob-ani-spin { to { transform: rotate(360deg); } }\n@keyframes iob-ani-draw { to { stroke-dashoffset: 0; } }\n@keyframes iob-ani-breathe { 50% { opacity: 0.35; } }\n@keyframes iob-ani-wave { 0%, 100% { opacity: 0.25; } 30% { opacity: 1; } }\n@keyframes iob-ani-shake { 20% { transform: translateX(-1.5px); } 40% { transform: translateX(1.5px); } 60% { transform: translateX(-1px); } 80% { transform: translateX(1px); } }\n\n@media (prefers-reduced-motion: reduce) {\n .iob-ani-pp-a, .iob-ani-pp-b, .iob-ani-menu-rot, .iob-ani-menu-bar, .iob-ani-trash-lid, .iob-ani-expert-shape, .iob-ani-folder-front, .iob-ani-folder-closed { transition-duration: 0.01ms; transition-delay: 0s; }\n .iob-ani-pp-pending .iob-ani-pp-ring { animation: iob-ani-breathe 1.2s ease-in-out infinite; }\n .iob-ani-res svg, .iob-ani-res svg * { animation: none !important; stroke-dashoffset: 0; }\n}\n`;\n\n/** Puts the style sheet of the animated icons into the page, once and before the first paint */\nexport function useAnimatedIconStyles(): void {\n useInsertionEffect(() => {\n if (!window.document.getElementById(STYLE_ID)) {\n const style = window.document.createElement('style');\n style.setAttribute('id', STYLE_ID);\n style.innerHTML = styles;\n window.document.head.appendChild(style);\n }\n }, []);\n}\n\n/** Properties of the root element: class, size and accessibility */\nexport function rootProps(props: AnimatedIconProps, className: string): React.HTMLAttributes<HTMLSpanElement> {\n // Without fontSize the size comes from the style sheet (24 px), so that MUI can change it like for its own icons\n let fontSize: string | number | undefined;\n if (typeof props.fontSize === 'number') {\n fontSize = props.fontSize;\n } else if (props.fontSize) {\n fontSize = SIZES[props.fontSize] || props.fontSize;\n }\n return {\n className: `iob-ani ${className}${props.className ? ` ${props.className}` : ''}`,\n style: fontSize === undefined ? props.style : { fontSize, ...props.style },\n role: props.ariaLabel ? 'img' : undefined,\n 'aria-label': props.ariaLabel,\n 'aria-hidden': props.ariaLabel ? undefined : true,\n };\n}\n\n/** True if the user asked the system for less motion */\nexport function prefersReducedMotion(): boolean {\n return !!window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;\n}\n\n/** Plays a one-time animation (Web Animations API), unless the user wants less motion */\nexport function play(\n element: Element | null | undefined,\n keyframes: Keyframe[],\n options: KeyframeAnimationOptions,\n): Animation | null {\n if (!element?.animate || prefersReducedMotion()) {\n return null;\n }\n return element.animate(keyframes, options);\n}\n\n/** Calls `onChange` when `value` changes, but not on the first render */\nexport function useChange<T>(value: T, onChange: (value: T, previous: T) => void): void {\n const previous = useRef(value);\n const callback = useRef(onChange);\n useEffect(() => {\n callback.current = onChange;\n });\n useEffect(() => {\n if (!Object.is(previous.current, value)) {\n const old = previous.current;\n previous.current = value;\n callback.current(value, old);\n }\n }, [value]);\n}\n"]}
|
|
@@ -4,7 +4,7 @@ import { AiOutlineLineChart as TypeIconChart } from 'react-icons/ai';
|
|
|
4
4
|
import { GoDeviceCameraVideo as TypeIconCamera } from 'react-icons/go';
|
|
5
5
|
import {
|
|
6
6
|
// FaExternalLinkSquareAlt as TypeIconURL,
|
|
7
|
-
FaImage as TypeIconImage, FaRegLightbulb as TypeIconDimmer, FaInfoCircle as TypeIconInfo, FaLightbulb as TypeIconLight, FaLock as TypeIconLock, FaStreetView as TypeIconLocation, FaStepForward as TypeIconMedia, FaSlidersH as TypeIconSlider, FaVolumeDown as TypeIconVolume, FaVolumeUp as TypeIconVolumeGroup, FaFan as TypeIconAC, FaWrench as TypeIconInstance, } from 'react-icons/fa';
|
|
7
|
+
FaImage as TypeIconImage, FaRegLightbulb as TypeIconDimmer, FaInfoCircle as TypeIconInfo, FaLightbulb as TypeIconLight, FaLock as TypeIconLock, FaStreetView as TypeIconLocation, FaStepForward as TypeIconMedia, FaSlidersH as TypeIconSlider, FaVolumeDown as TypeIconVolume, FaVolumeUp as TypeIconVolumeGroup, FaFan as TypeIconAC, FaWrench as TypeIconInstance, FaTv as TypeIconTv, } from 'react-icons/fa';
|
|
8
8
|
import { MdFormatColorFill as TypeIconHUE, MdFormatColorFill as TypeIconCT, MdWarning as TypeIconWarning, MdQuestionMark as TypeIconUnknown, MdOutlineMyLocation as TypeIconLocationOne, MdDeviceHub as TypeIconHub3, MdPolyline as TypeIconNode, MdHub as TypeIconHub5, MdControlCamera as TypeIconController, MdAir as TypeIconAirQuality, MdElectricMeter as TypeIconElectricity, } from 'react-icons/md';
|
|
9
9
|
import { WiCloudy as TypeIconWeather } from 'react-icons/wi';
|
|
10
10
|
import { IoIosRadioButtonOn as TypeIconButtonSensor } from 'react-icons/io';
|
|
@@ -71,6 +71,7 @@ const TYPE_ICONS = {
|
|
|
71
71
|
[Types.socket]: TypeIconSocket,
|
|
72
72
|
[Types.temperature]: TypeIconTemperature,
|
|
73
73
|
[Types.thermostat]: TypeIconThermostat,
|
|
74
|
+
[Types.tv]: TypeIconTv,
|
|
74
75
|
// [Types.valve]: TypeIconValve,
|
|
75
76
|
[Types.vacuumCleaner]: TypeIconVacuumCleaner,
|
|
76
77
|
[Types.volume]: TypeIconVolume,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceTypeIcon.js","sourceRoot":"./src/","sources":["Components/DeviceType/DeviceTypeIcon.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect } from 'react';\n\nimport { Box, Tooltip } from '@mui/material';\n\nimport { AiOutlineLineChart as TypeIconChart } from 'react-icons/ai';\nimport { GoDeviceCameraVideo as TypeIconCamera } from 'react-icons/go';\n\nimport {\n // FaExternalLinkSquareAlt as TypeIconURL,\n FaImage as TypeIconImage,\n FaRegLightbulb as TypeIconDimmer,\n FaInfoCircle as TypeIconInfo,\n FaLightbulb as TypeIconLight,\n FaLock as TypeIconLock,\n FaStreetView as TypeIconLocation,\n FaStepForward as TypeIconMedia,\n FaSlidersH as TypeIconSlider,\n FaVolumeDown as TypeIconVolume,\n FaVolumeUp as TypeIconVolumeGroup,\n FaFan as TypeIconAC,\n FaWrench as TypeIconInstance,\n} from 'react-icons/fa';\n\nimport {\n MdFormatColorFill as TypeIconHUE,\n MdFormatColorFill as TypeIconCT,\n MdWarning as TypeIconWarning,\n MdQuestionMark as TypeIconUnknown,\n MdOutlineMyLocation as TypeIconLocationOne,\n MdDeviceHub as TypeIconHub3,\n MdPolyline as TypeIconNode,\n MdHub as TypeIconHub5,\n MdControlCamera as TypeIconController,\n MdAir as TypeIconAirQuality,\n MdElectricMeter as TypeIconElectricity,\n} from 'react-icons/md';\nimport { WiCloudy as TypeIconWeather } from 'react-icons/wi';\nimport { IoIosRadioButtonOn as TypeIconButtonSensor } from 'react-icons/io';\nimport {\n TbSunElectricity as TypeIconIlluminance,\n TbAlarmSmoke as TypeIconCoAlarm,\n TbBarrel as TypeIconFillLevel,\n TbRipple as TypeIconFlow,\n TbGauge as TypeIconPressure,\n TbEngine as TypeIconPump,\n TbCircuitSwitchClosed as TypeIconContact,\n} from 'react-icons/tb';\nimport { PiPaletteDuotone as TypeIconRGBWSingle, PiFan as TypeIconFan } from 'react-icons/pi';\nimport { LuAirVent as TypeIconAirPurifier } from 'react-icons/lu';\n\nimport { Types } from '@iobroker/type-detector';\n\nimport { I18n } from '../../i18n';\nimport { Icon } from '../Icon';\n\nimport {\n Cleaner as TypeIconVacuumCleaner,\n Humidity as TypeIconHumidity,\n Jalousie as TypeIconBlinds,\n PushButton as TypeIconButton,\n DoorOpened as TypeIconDoor,\n FireOn as TypeIconFireAlarm,\n FloodOn as TypeIconFloodAlarm,\n Gate as TypeIconGate,\n MotionOn as TypeIconMotion,\n RGB as TypeIconRGB,\n Socket as TypeIconSocket,\n Thermometer as TypeIconTemperature,\n Thermostat as TypeIconThermostat,\n // HeatValve as TypeIconValve,\n WindowOpened as TypeIconWindow,\n WindowTilted as TypeIconWindowTilt,\n type IconPropsSVG,\n} from './icons';\nimport { extendDeviceTypeTranslation } from './deviceTypeTranslations';\n\nexport type TypesExtended = Types | 'invalid' | 'hub3' | 'node' | 'hub5' | 'controller';\n\n/**\n * Icon for every device type.\n *\n * This map is deliberately a complete `Record` over `TypesExtended`: when `@iobroker/type-detector`\n * adds a new member to `Types`, the build fails here until an icon is assigned. Never add keys that\n * are not part of `TypesExtended` (a single `@ts-expect-error` inside the literal would suppress the\n * completeness check for the whole object) — put those in `ROLE_ICONS` below.\n */\nconst TYPE_ICONS: Record<TypesExtended, React.FC<IconPropsSVG>> = {\n [Types.airCondition]: TypeIconAC,\n [Types.airPurifier]: TypeIconAirPurifier,\n [Types.airQuality]: TypeIconAirQuality,\n [Types.blind]: TypeIconBlinds,\n [Types.blindButtons]: TypeIconBlinds,\n [Types.button]: TypeIconButton,\n [Types.buttonSensor]: TypeIconButtonSensor,\n [Types.camera]: TypeIconCamera,\n [Types.chart]: TypeIconChart,\n [Types.coAlarm]: TypeIconCoAlarm,\n [Types.contact]: TypeIconContact,\n // [Types.url]: TypeIconURL,\n [Types.image]: TypeIconImage,\n [Types.dimmer]: TypeIconDimmer,\n [Types.door]: TypeIconDoor,\n [Types.electricity]: TypeIconElectricity,\n [Types.fan]: TypeIconFan,\n [Types.fillLevel]: TypeIconFillLevel,\n [Types.fireAlarm]: TypeIconFireAlarm,\n [Types.floodAlarm]: TypeIconFloodAlarm,\n [Types.flow]: TypeIconFlow,\n [Types.gate]: TypeIconGate,\n [Types.humidity]: TypeIconHumidity,\n [Types.illuminance]: TypeIconIlluminance,\n [Types.info]: TypeIconInfo,\n [Types.light]: TypeIconLight,\n [Types.lock]: TypeIconLock,\n [Types.location]: TypeIconLocation,\n [Types.locationOne]: TypeIconLocationOne,\n [Types.media]: TypeIconMedia,\n [Types.motion]: TypeIconMotion,\n [Types.ct]: TypeIconCT,\n [Types.percentage]: TypeIconSlider,\n [Types.pressure]: TypeIconPressure,\n [Types.pump]: TypeIconPump,\n [Types.rgb]: TypeIconRGB,\n [Types.rgbSingle]: TypeIconRGB,\n [Types.rgbwSingle]: TypeIconRGBWSingle,\n [Types.hue]: TypeIconHUE,\n [Types.cie]: TypeIconRGB,\n [Types.slider]: TypeIconSlider,\n [Types.socket]: TypeIconSocket,\n [Types.temperature]: TypeIconTemperature,\n [Types.thermostat]: TypeIconThermostat,\n // [Types.valve]: TypeIconValve,\n [Types.vacuumCleaner]: TypeIconVacuumCleaner,\n [Types.volume]: TypeIconVolume,\n [Types.volumeGroup]: TypeIconVolumeGroup,\n [Types.window]: TypeIconWindow,\n [Types.windowTilt]: TypeIconWindowTilt,\n [Types.weatherCurrent]: TypeIconWeather,\n [Types.weatherForecast]: TypeIconWeather,\n [Types.warning]: TypeIconWarning,\n\n [Types.unknown]: TypeIconUnknown,\n [Types.instance]: TypeIconInstance,\n\n // Special matter types\n invalid: TypeIconWarning,\n hub3: TypeIconHub3,\n node: TypeIconNode,\n hub5: TypeIconHub5,\n controller: TypeIconController,\n};\n\n/** Icons for state roles that may be given as `src` instead of a device type */\nconst ROLE_ICONS: Record<string, React.FC<IconPropsSVG>> = {\n 'sensor.alarm.fire': TypeIconFireAlarm,\n 'sensor.alarm.flood': TypeIconFloodAlarm,\n};\n\nconst ALL_ICONS: Record<string, React.FC<IconPropsSVG>> = { ...TYPE_ICONS, ...ROLE_ICONS };\n\nfunction isKnownIcon(src: unknown): src is TypesExtended {\n return typeof src === 'string' && Object.prototype.hasOwnProperty.call(ALL_ICONS, src);\n}\n\nconst defaultStyle: React.CSSProperties = {\n width: 32,\n height: 32,\n};\n\nexport interface IconProps {\n /** URL, UTF-8 character, or svg code (data:image/svg...) */\n src?: string | React.JSX.Element | null | undefined;\n /** Class name */\n className?: string;\n /** Style for image */\n style?: React.CSSProperties;\n /** Styles for mui */\n sx?: Record<string, any>;\n /** Tooltip */\n title?: string | true;\n /** Styles for utf-8 characters */\n styleUTF8?: React.CSSProperties;\n /** On error handler */\n onError?: React.ReactEventHandler<HTMLImageElement>;\n /** Reference to image */\n ref?: React.RefObject<HTMLImageElement>;\n /** Alternative text for image */\n alt?: string;\n /** On click handler */\n onClick?: React.MouseEventHandler<any>;\n}\n\nexport type TypeIconProps = IconProps & { type?: TypesExtended };\n\nexport function DeviceTypeIcon(props: TypeIconProps): React.JSX.Element | null {\n const [loaded, setLoaded] = React.useState(false);\n\n useEffect(() => {\n if (props.title && !loaded) {\n extendDeviceTypeTranslation();\n setLoaded(true);\n }\n }, [props.title, loaded]);\n\n if (!loaded && props.title) {\n return (\n <Box\n style={{ ...defaultStyle, ...(props.style || undefined) }}\n className={props.className}\n sx={props.sx}\n />\n );\n }\n // src could contain a device type or a state role too, so detect if it is a type\n const type: TypesExtended | undefined = props.type || (isKnownIcon(props.src) ? props.src : undefined);\n\n if (!type && props.src) {\n return (\n <Icon\n style={defaultStyle}\n {...props}\n title={props.title === true ? undefined : props.title}\n src={props.src}\n />\n );\n }\n\n const TypeIcon = type && ALL_ICONS[type];\n if (!TypeIcon) {\n // Show the first letter of a type\n return type ? (\n <span style={{ ...defaultStyle, ...(props.style || undefined) }}>{type[0].toUpperCase()}</span>\n ) : null;\n }\n\n const icon = (\n <TypeIcon\n style={{ ...defaultStyle, ...(props.style || undefined) }}\n onClick={props.onClick}\n className={props.className}\n sx={props.sx}\n />\n );\n\n if (props.title) {\n return (\n <Tooltip\n slotProps={{ popper: { sx: { pointerEvents: 'none' } } }}\n title={props.title === true ? I18n.t(`type-${type}`) : props.title}\n >\n <div style={{ display: 'flex' }}>{icon}</div>\n </Tooltip>\n );\n }\n\n return icon;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"DeviceTypeIcon.js","sourceRoot":"./src/","sources":["Components/DeviceType/DeviceTypeIcon.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect } from 'react';\n\nimport { Box, Tooltip } from '@mui/material';\n\nimport { AiOutlineLineChart as TypeIconChart } from 'react-icons/ai';\nimport { GoDeviceCameraVideo as TypeIconCamera } from 'react-icons/go';\n\nimport {\n // FaExternalLinkSquareAlt as TypeIconURL,\n FaImage as TypeIconImage,\n FaRegLightbulb as TypeIconDimmer,\n FaInfoCircle as TypeIconInfo,\n FaLightbulb as TypeIconLight,\n FaLock as TypeIconLock,\n FaStreetView as TypeIconLocation,\n FaStepForward as TypeIconMedia,\n FaSlidersH as TypeIconSlider,\n FaVolumeDown as TypeIconVolume,\n FaVolumeUp as TypeIconVolumeGroup,\n FaFan as TypeIconAC,\n FaWrench as TypeIconInstance,\n FaTv as TypeIconTv,\n} from 'react-icons/fa';\n\nimport {\n MdFormatColorFill as TypeIconHUE,\n MdFormatColorFill as TypeIconCT,\n MdWarning as TypeIconWarning,\n MdQuestionMark as TypeIconUnknown,\n MdOutlineMyLocation as TypeIconLocationOne,\n MdDeviceHub as TypeIconHub3,\n MdPolyline as TypeIconNode,\n MdHub as TypeIconHub5,\n MdControlCamera as TypeIconController,\n MdAir as TypeIconAirQuality,\n MdElectricMeter as TypeIconElectricity,\n} from 'react-icons/md';\nimport { WiCloudy as TypeIconWeather } from 'react-icons/wi';\nimport { IoIosRadioButtonOn as TypeIconButtonSensor } from 'react-icons/io';\nimport {\n TbSunElectricity as TypeIconIlluminance,\n TbAlarmSmoke as TypeIconCoAlarm,\n TbBarrel as TypeIconFillLevel,\n TbRipple as TypeIconFlow,\n TbGauge as TypeIconPressure,\n TbEngine as TypeIconPump,\n TbCircuitSwitchClosed as TypeIconContact,\n} from 'react-icons/tb';\nimport { PiPaletteDuotone as TypeIconRGBWSingle, PiFan as TypeIconFan } from 'react-icons/pi';\nimport { LuAirVent as TypeIconAirPurifier } from 'react-icons/lu';\n\nimport { Types } from '@iobroker/type-detector';\n\nimport { I18n } from '../../i18n';\nimport { Icon } from '../Icon';\n\nimport {\n Cleaner as TypeIconVacuumCleaner,\n Humidity as TypeIconHumidity,\n Jalousie as TypeIconBlinds,\n PushButton as TypeIconButton,\n DoorOpened as TypeIconDoor,\n FireOn as TypeIconFireAlarm,\n FloodOn as TypeIconFloodAlarm,\n Gate as TypeIconGate,\n MotionOn as TypeIconMotion,\n RGB as TypeIconRGB,\n Socket as TypeIconSocket,\n Thermometer as TypeIconTemperature,\n Thermostat as TypeIconThermostat,\n // HeatValve as TypeIconValve,\n WindowOpened as TypeIconWindow,\n WindowTilted as TypeIconWindowTilt,\n type IconPropsSVG,\n} from './icons';\nimport { extendDeviceTypeTranslation } from './deviceTypeTranslations';\n\nexport type TypesExtended = Types | 'invalid' | 'hub3' | 'node' | 'hub5' | 'controller';\n\n/**\n * Icon for every device type.\n *\n * This map is deliberately a complete `Record` over `TypesExtended`: when `@iobroker/type-detector`\n * adds a new member to `Types`, the build fails here until an icon is assigned. Never add keys that\n * are not part of `TypesExtended` (a single `@ts-expect-error` inside the literal would suppress the\n * completeness check for the whole object) — put those in `ROLE_ICONS` below.\n */\nconst TYPE_ICONS: Record<TypesExtended, React.FC<IconPropsSVG>> = {\n [Types.airCondition]: TypeIconAC,\n [Types.airPurifier]: TypeIconAirPurifier,\n [Types.airQuality]: TypeIconAirQuality,\n [Types.blind]: TypeIconBlinds,\n [Types.blindButtons]: TypeIconBlinds,\n [Types.button]: TypeIconButton,\n [Types.buttonSensor]: TypeIconButtonSensor,\n [Types.camera]: TypeIconCamera,\n [Types.chart]: TypeIconChart,\n [Types.coAlarm]: TypeIconCoAlarm,\n [Types.contact]: TypeIconContact,\n // [Types.url]: TypeIconURL,\n [Types.image]: TypeIconImage,\n [Types.dimmer]: TypeIconDimmer,\n [Types.door]: TypeIconDoor,\n [Types.electricity]: TypeIconElectricity,\n [Types.fan]: TypeIconFan,\n [Types.fillLevel]: TypeIconFillLevel,\n [Types.fireAlarm]: TypeIconFireAlarm,\n [Types.floodAlarm]: TypeIconFloodAlarm,\n [Types.flow]: TypeIconFlow,\n [Types.gate]: TypeIconGate,\n [Types.humidity]: TypeIconHumidity,\n [Types.illuminance]: TypeIconIlluminance,\n [Types.info]: TypeIconInfo,\n [Types.light]: TypeIconLight,\n [Types.lock]: TypeIconLock,\n [Types.location]: TypeIconLocation,\n [Types.locationOne]: TypeIconLocationOne,\n [Types.media]: TypeIconMedia,\n [Types.motion]: TypeIconMotion,\n [Types.ct]: TypeIconCT,\n [Types.percentage]: TypeIconSlider,\n [Types.pressure]: TypeIconPressure,\n [Types.pump]: TypeIconPump,\n [Types.rgb]: TypeIconRGB,\n [Types.rgbSingle]: TypeIconRGB,\n [Types.rgbwSingle]: TypeIconRGBWSingle,\n [Types.hue]: TypeIconHUE,\n [Types.cie]: TypeIconRGB,\n [Types.slider]: TypeIconSlider,\n [Types.socket]: TypeIconSocket,\n [Types.temperature]: TypeIconTemperature,\n [Types.thermostat]: TypeIconThermostat,\n [Types.tv]: TypeIconTv,\n // [Types.valve]: TypeIconValve,\n [Types.vacuumCleaner]: TypeIconVacuumCleaner,\n [Types.volume]: TypeIconVolume,\n [Types.volumeGroup]: TypeIconVolumeGroup,\n [Types.window]: TypeIconWindow,\n [Types.windowTilt]: TypeIconWindowTilt,\n [Types.weatherCurrent]: TypeIconWeather,\n [Types.weatherForecast]: TypeIconWeather,\n [Types.warning]: TypeIconWarning,\n\n [Types.unknown]: TypeIconUnknown,\n [Types.instance]: TypeIconInstance,\n\n // Special matter types\n invalid: TypeIconWarning,\n hub3: TypeIconHub3,\n node: TypeIconNode,\n hub5: TypeIconHub5,\n controller: TypeIconController,\n};\n\n/** Icons for state roles that may be given as `src` instead of a device type */\nconst ROLE_ICONS: Record<string, React.FC<IconPropsSVG>> = {\n 'sensor.alarm.fire': TypeIconFireAlarm,\n 'sensor.alarm.flood': TypeIconFloodAlarm,\n};\n\nconst ALL_ICONS: Record<string, React.FC<IconPropsSVG>> = { ...TYPE_ICONS, ...ROLE_ICONS };\n\nfunction isKnownIcon(src: unknown): src is TypesExtended {\n return typeof src === 'string' && Object.prototype.hasOwnProperty.call(ALL_ICONS, src);\n}\n\nconst defaultStyle: React.CSSProperties = {\n width: 32,\n height: 32,\n};\n\nexport interface IconProps {\n /** URL, UTF-8 character, or svg code (data:image/svg...) */\n src?: string | React.JSX.Element | null | undefined;\n /** Class name */\n className?: string;\n /** Style for image */\n style?: React.CSSProperties;\n /** Styles for mui */\n sx?: Record<string, any>;\n /** Tooltip */\n title?: string | true;\n /** Styles for utf-8 characters */\n styleUTF8?: React.CSSProperties;\n /** On error handler */\n onError?: React.ReactEventHandler<HTMLImageElement>;\n /** Reference to image */\n ref?: React.RefObject<HTMLImageElement>;\n /** Alternative text for image */\n alt?: string;\n /** On click handler */\n onClick?: React.MouseEventHandler<any>;\n}\n\nexport type TypeIconProps = IconProps & { type?: TypesExtended };\n\nexport function DeviceTypeIcon(props: TypeIconProps): React.JSX.Element | null {\n const [loaded, setLoaded] = React.useState(false);\n\n useEffect(() => {\n if (props.title && !loaded) {\n extendDeviceTypeTranslation();\n setLoaded(true);\n }\n }, [props.title, loaded]);\n\n if (!loaded && props.title) {\n return (\n <Box\n style={{ ...defaultStyle, ...(props.style || undefined) }}\n className={props.className}\n sx={props.sx}\n />\n );\n }\n // src could contain a device type or a state role too, so detect if it is a type\n const type: TypesExtended | undefined = props.type || (isKnownIcon(props.src) ? props.src : undefined);\n\n if (!type && props.src) {\n return (\n <Icon\n style={defaultStyle}\n {...props}\n title={props.title === true ? undefined : props.title}\n src={props.src}\n />\n );\n }\n\n const TypeIcon = type && ALL_ICONS[type];\n if (!TypeIcon) {\n // Show the first letter of a type\n return type ? (\n <span style={{ ...defaultStyle, ...(props.style || undefined) }}>{type[0].toUpperCase()}</span>\n ) : null;\n }\n\n const icon = (\n <TypeIcon\n style={{ ...defaultStyle, ...(props.style || undefined) }}\n onClick={props.onClick}\n className={props.className}\n sx={props.sx}\n />\n );\n\n if (props.title) {\n return (\n <Tooltip\n slotProps={{ popper: { sx: { pointerEvents: 'none' } } }}\n title={props.title === true ? I18n.t(`type-${type}`) : props.title}\n >\n <div style={{ display: 'flex' }}>{icon}</div>\n </Tooltip>\n );\n }\n\n return icon;\n}\n"]}
|