@iobroker/gui-components 10.3.14 → 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 +8 -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/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 +1 -1
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ npm create vite@latest src -- --template react-ts
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@emotion/react": "^11.14.0",
|
|
38
38
|
"@emotion/styled": "^11.14.1",
|
|
39
|
-
"@iobroker/gui-components": "^10.3.
|
|
39
|
+
"@iobroker/gui-components": "^10.3.15",
|
|
40
40
|
"@mui/icons-material": "^9.0.1",
|
|
41
41
|
"@mui/material": "^9.0.1",
|
|
42
42
|
"react": "^19.2.5",
|
|
@@ -877,6 +877,13 @@ You can find the migration instructions:
|
|
|
877
877
|
-->
|
|
878
878
|
|
|
879
879
|
## Changelog
|
|
880
|
+
### 10.3.15 (2026-11-03)
|
|
881
|
+
- (@GermanBluefox) Added: animated icons `IconPlayPause`, `IconStatusLed`, `IconResult`, `IconRefresh`, `IconBell`, `IconMenuArrow`, `IconTrash`, `IconConnectionState`, `IconExpertMode` and `IconFolder` (CSS/SVG)
|
|
882
|
+
- (@GermanBluefox) Changed: the object browser uses the animated reload and delete icons
|
|
883
|
+
- (@GermanBluefox) Changed: new expert mode symbol (mortarboard) in the object and file browser
|
|
884
|
+
- (@GermanBluefox) Changed: object browser: folders open with an animation, the children slide out from under the row
|
|
885
|
+
- (@GermanBluefox) Changed: new loading screen `LoaderCommunity` with the props `status`, `done` and `onFinished`; the previous one is `LoaderCommunityLegacy`
|
|
886
|
+
|
|
880
887
|
### 10.3.14 (2026-10-25)
|
|
881
888
|
- (@GermanBluefox) Added Icons and texts for new type: TV
|
|
882
889
|
|
|
@@ -0,0 +1,21 @@
|
|
|
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 IconBellProps extends AnimatedIconProps {
|
|
9
|
+
/** Number of the notifications: the bell rings when it grows (not when it gets smaller) */
|
|
10
|
+
count?: number;
|
|
11
|
+
/** Every change of this value rings the bell too */
|
|
12
|
+
ring?: string | number | boolean | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Notification bell, which rings when a new notification arrives.
|
|
16
|
+
*
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <Badge badgeContent={count}><IconBell count={count} /></Badge>
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function IconBell(props: IconBellProps): React.JSX.Element;
|
|
@@ -0,0 +1,50 @@
|
|
|
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
|
+
/**
|
|
9
|
+
* Notification bell, which rings when a new notification arrives.
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <Badge badgeContent={count}><IconBell count={count} /></Badge>
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function IconBell(props) {
|
|
16
|
+
useAnimatedIconStyles();
|
|
17
|
+
const body = useRef(null);
|
|
18
|
+
const clapper = useRef(null);
|
|
19
|
+
const ringBell = () => {
|
|
20
|
+
play(body.current, [
|
|
21
|
+
{ transform: 'rotate(0deg)' },
|
|
22
|
+
{ transform: 'rotate(16deg)' },
|
|
23
|
+
{ transform: 'rotate(-14deg)' },
|
|
24
|
+
{ transform: 'rotate(10deg)' },
|
|
25
|
+
{ transform: 'rotate(-6deg)' },
|
|
26
|
+
{ transform: 'rotate(3deg)' },
|
|
27
|
+
{ transform: 'rotate(0deg)' },
|
|
28
|
+
], { duration: 900, easing: 'ease-in-out' });
|
|
29
|
+
play(clapper.current, [
|
|
30
|
+
{ transform: 'translateX(0)' },
|
|
31
|
+
{ transform: 'translateX(-1.8px)' },
|
|
32
|
+
{ transform: 'translateX(1.8px)' },
|
|
33
|
+
{ transform: 'translateX(-1.2px)' },
|
|
34
|
+
{ transform: 'translateX(0.6px)' },
|
|
35
|
+
{ transform: 'translateX(0)' },
|
|
36
|
+
], { duration: 900, delay: 60, easing: 'ease-in-out' });
|
|
37
|
+
};
|
|
38
|
+
useChange(props.count || 0, (count, previous) => {
|
|
39
|
+
if (count > previous) {
|
|
40
|
+
ringBell();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
useChange(props.ring, ringBell);
|
|
44
|
+
return (React.createElement("span", { ...rootProps(props, 'iob-ani-bell') },
|
|
45
|
+
React.createElement("svg", { viewBox: "0 0 24 24" },
|
|
46
|
+
React.createElement("g", { className: "iob-ani-bell-body", ref: body },
|
|
47
|
+
React.createElement("path", { fill: "currentColor", d: "M18 16v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z" })),
|
|
48
|
+
React.createElement("path", { ref: clapper, fill: "currentColor", d: "M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2z" }))));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=IconBell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconBell.js","sourceRoot":"./src/","sources":["Components/AnimatedIcons/IconBell.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAA0B,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AASrG;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAoB;IACzC,qBAAqB,EAAE,CAAC;IACxB,MAAM,IAAI,GAAG,MAAM,CAAc,IAAI,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAE7C,MAAM,QAAQ,GAAG,GAAS,EAAE;QACxB,IAAI,CACA,IAAI,CAAC,OAAO,EACZ;YACI,EAAE,SAAS,EAAE,cAAc,EAAE;YAC7B,EAAE,SAAS,EAAE,eAAe,EAAE;YAC9B,EAAE,SAAS,EAAE,gBAAgB,EAAE;YAC/B,EAAE,SAAS,EAAE,eAAe,EAAE;YAC9B,EAAE,SAAS,EAAE,eAAe,EAAE;YAC9B,EAAE,SAAS,EAAE,cAAc,EAAE;YAC7B,EAAE,SAAS,EAAE,cAAc,EAAE;SAChC,EACD,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,CAC3C,CAAC;QACF,IAAI,CACA,OAAO,CAAC,OAAO,EACf;YACI,EAAE,SAAS,EAAE,eAAe,EAAE;YAC9B,EAAE,SAAS,EAAE,oBAAoB,EAAE;YACnC,EAAE,SAAS,EAAE,mBAAmB,EAAE;YAClC,EAAE,SAAS,EAAE,oBAAoB,EAAE;YACnC,EAAE,SAAS,EAAE,mBAAmB,EAAE;YAClC,EAAE,SAAS,EAAE,eAAe,EAAE;SACjC,EACD,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,CACtD,CAAC;IACN,CAAC,CAAC;IAEF,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;QAC5C,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;YACnB,QAAQ,EAAE,CAAC;QACf,CAAC;IACL,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAEhC,OAAO,CACH,iCAAU,SAAS,CAAC,KAAK,EAAE,cAAc,CAAC;QACtC,6BAAK,OAAO,EAAC,WAAW;YACpB,2BACI,SAAS,EAAC,mBAAmB,EAC7B,GAAG,EAAE,IAAI;gBAET,8BACI,IAAI,EAAC,cAAc,EACnB,CAAC,EAAC,4HAA4H,GAChI,CACF;YACJ,8BACI,GAAG,EAAE,OAAO,EACZ,IAAI,EAAC,cAAc,EACnB,CAAC,EAAC,0CAA0C,GAC9C,CACA,CACH,CACV,CAAC;AACN,CAAC","sourcesContent":["/**\n * Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>\n *\n * MIT License\n */\nimport React, { useRef } from 'react';\nimport { type AnimatedIconProps, play, rootProps, useAnimatedIconStyles, useChange } from './common';\n\nexport interface IconBellProps extends AnimatedIconProps {\n /** Number of the notifications: the bell rings when it grows (not when it gets smaller) */\n count?: number;\n /** Every change of this value rings the bell too */\n ring?: string | number | boolean | null;\n}\n\n/**\n * Notification bell, which rings when a new notification arrives.\n *\n * ```tsx\n * <Badge badgeContent={count}><IconBell count={count} /></Badge>\n * ```\n */\nexport function IconBell(props: IconBellProps): React.JSX.Element {\n useAnimatedIconStyles();\n const body = useRef<SVGGElement>(null);\n const clapper = useRef<SVGPathElement>(null);\n\n const ringBell = (): void => {\n play(\n body.current,\n [\n { transform: 'rotate(0deg)' },\n { transform: 'rotate(16deg)' },\n { transform: 'rotate(-14deg)' },\n { transform: 'rotate(10deg)' },\n { transform: 'rotate(-6deg)' },\n { transform: 'rotate(3deg)' },\n { transform: 'rotate(0deg)' },\n ],\n { duration: 900, easing: 'ease-in-out' },\n );\n play(\n clapper.current,\n [\n { transform: 'translateX(0)' },\n { transform: 'translateX(-1.8px)' },\n { transform: 'translateX(1.8px)' },\n { transform: 'translateX(-1.2px)' },\n { transform: 'translateX(0.6px)' },\n { transform: 'translateX(0)' },\n ],\n { duration: 900, delay: 60, easing: 'ease-in-out' },\n );\n };\n\n useChange(props.count || 0, (count, previous) => {\n if (count > previous) {\n ringBell();\n }\n });\n useChange(props.ring, ringBell);\n\n return (\n <span {...rootProps(props, 'iob-ani-bell')}>\n <svg viewBox=\"0 0 24 24\">\n <g\n className=\"iob-ani-bell-body\"\n ref={body}\n >\n <path\n fill=\"currentColor\"\n d=\"M18 16v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z\"\n />\n </g>\n <path\n ref={clapper}\n fill=\"currentColor\"\n d=\"M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2z\"\n />\n </svg>\n </span>\n );\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
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 IconConnectionStateProps extends AnimatedIconProps {
|
|
9
|
+
/** connected: all waves, connecting: the waves run outwards, disconnected: dimmed and crossed out */
|
|
10
|
+
state: 'connected' | 'connecting' | 'disconnected';
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Connection symbol with three states.
|
|
14
|
+
*
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <IconConnectionState state={connected ? 'connected' : reconnecting ? 'connecting' : 'disconnected'} />
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function IconConnectionState(props: IconConnectionStateProps): React.JSX.Element;
|
|
@@ -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 { rootProps, useAnimatedIconStyles } from './common';
|
|
8
|
+
/**
|
|
9
|
+
* Connection symbol with three states.
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <IconConnectionState state={connected ? 'connected' : reconnecting ? 'connecting' : 'disconnected'} />
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function IconConnectionState(props) {
|
|
16
|
+
useAnimatedIconStyles();
|
|
17
|
+
return (React.createElement("span", { ...rootProps(props, `iob-ani-wifi iob-ani-wifi-${props.state}`) },
|
|
18
|
+
React.createElement("svg", { viewBox: "0 0 24 24" },
|
|
19
|
+
React.createElement("path", { className: "iob-ani-wifi-w iob-ani-wifi-w3", d: "M2.45 8.95A13.5 13.5 0 0 1 21.55 8.95" }),
|
|
20
|
+
React.createElement("path", { className: "iob-ani-wifi-w iob-ani-wifi-w2", d: "M5.64 12.14A9 9 0 0 1 18.36 12.14" }),
|
|
21
|
+
React.createElement("path", { className: "iob-ani-wifi-w iob-ani-wifi-w1", d: "M8.82 15.32A4.5 4.5 0 0 1 15.18 15.32" }),
|
|
22
|
+
React.createElement("circle", { className: "iob-ani-wifi-w", cx: "12", cy: "18.5", r: "1.7" }),
|
|
23
|
+
React.createElement("path", { className: "iob-ani-wifi-slash", d: "M4 3.5L20 20.5", pathLength: 1 }))));
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=IconConnectionState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconConnectionState.js","sourceRoot":"./src/","sources":["Components/AnimatedIcons/IconConnectionState.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAA0B,SAAS,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAOpF;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAA+B;IAC/D,qBAAqB,EAAE,CAAC;IACxB,OAAO,CACH,iCAAU,SAAS,CAAC,KAAK,EAAE,6BAA6B,KAAK,CAAC,KAAK,EAAE,CAAC;QAClE,6BAAK,OAAO,EAAC,WAAW;YACpB,8BACI,SAAS,EAAC,gCAAgC,EAC1C,CAAC,EAAC,uCAAuC,GAC3C;YACF,8BACI,SAAS,EAAC,gCAAgC,EAC1C,CAAC,EAAC,mCAAmC,GACvC;YACF,8BACI,SAAS,EAAC,gCAAgC,EAC1C,CAAC,EAAC,uCAAuC,GAC3C;YACF,gCACI,SAAS,EAAC,gBAAgB,EAC1B,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,MAAM,EACT,CAAC,EAAC,KAAK,GACT;YACF,8BACI,SAAS,EAAC,oBAAoB,EAC9B,CAAC,EAAC,gBAAgB,EAClB,UAAU,EAAE,CAAC,GACf,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 IconConnectionStateProps extends AnimatedIconProps {\n /** connected: all waves, connecting: the waves run outwards, disconnected: dimmed and crossed out */\n state: 'connected' | 'connecting' | 'disconnected';\n}\n\n/**\n * Connection symbol with three states.\n *\n * ```tsx\n * <IconConnectionState state={connected ? 'connected' : reconnecting ? 'connecting' : 'disconnected'} />\n * ```\n */\nexport function IconConnectionState(props: IconConnectionStateProps): React.JSX.Element {\n useAnimatedIconStyles();\n return (\n <span {...rootProps(props, `iob-ani-wifi iob-ani-wifi-${props.state}`)}>\n <svg viewBox=\"0 0 24 24\">\n <path\n className=\"iob-ani-wifi-w iob-ani-wifi-w3\"\n d=\"M2.45 8.95A13.5 13.5 0 0 1 21.55 8.95\"\n />\n <path\n className=\"iob-ani-wifi-w iob-ani-wifi-w2\"\n d=\"M5.64 12.14A9 9 0 0 1 18.36 12.14\"\n />\n <path\n className=\"iob-ani-wifi-w iob-ani-wifi-w1\"\n d=\"M8.82 15.32A4.5 4.5 0 0 1 15.18 15.32\"\n />\n <circle\n className=\"iob-ani-wifi-w\"\n cx=\"12\"\n cy=\"18.5\"\n r=\"1.7\"\n />\n <path\n className=\"iob-ani-wifi-slash\"\n d=\"M4 3.5L20 20.5\"\n pathLength={1}\n />\n </svg>\n </span>\n );\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
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 IconExpertModeProps extends AnimatedIconProps {
|
|
9
|
+
/** The expert mode is on: the hat is filled. Switching it on lets the hat fly up. */
|
|
10
|
+
active: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Expert mode symbol: a mortarboard. Off it is only outlined, on it is filled, so both states differ also
|
|
14
|
+
* without color. When the expert mode is switched on, the hat flies up a little and the tassel swings.
|
|
15
|
+
*
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <IconButton onClick={() => this.toggleExpertMode()}>
|
|
18
|
+
* <IconExpertMode active={this.state.expertMode} />
|
|
19
|
+
* </IconButton>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function IconExpertMode(props: IconExpertModeProps): React.JSX.Element;
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
const rotate = (deg) => ({ transform: `rotate(${deg}deg)` });
|
|
9
|
+
/**
|
|
10
|
+
* Expert mode symbol: a mortarboard. Off it is only outlined, on it is filled, so both states differ also
|
|
11
|
+
* without color. When the expert mode is switched on, the hat flies up a little and the tassel swings.
|
|
12
|
+
*
|
|
13
|
+
* ```tsx
|
|
14
|
+
* <IconButton onClick={() => this.toggleExpertMode()}>
|
|
15
|
+
* <IconExpertMode active={this.state.expertMode} />
|
|
16
|
+
* </IconButton>
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function IconExpertMode(props) {
|
|
20
|
+
useAnimatedIconStyles();
|
|
21
|
+
const hat = useRef(null);
|
|
22
|
+
const tassel = useRef(null);
|
|
23
|
+
useChange(props.active, active => {
|
|
24
|
+
if (active) {
|
|
25
|
+
play(hat.current, [
|
|
26
|
+
{ transform: 'translateY(0) rotate(0deg)' },
|
|
27
|
+
{ transform: 'translateY(-3.5px) rotate(-10deg)', offset: 0.38 },
|
|
28
|
+
{ transform: 'translateY(0.6px) rotate(2deg)', offset: 0.72 },
|
|
29
|
+
{ transform: 'translateY(0) rotate(0deg)' },
|
|
30
|
+
], { duration: 700, easing: 'ease-out' });
|
|
31
|
+
play(tassel.current, [0, -40, 16, -8, 3, 0].map(rotate), { duration: 1100, easing: 'ease-out' });
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
play(hat.current, [{ transform: 'translateY(0)' }, { transform: 'translateY(0.8px)' }, { transform: 'translateY(0)' }], { duration: 260 });
|
|
35
|
+
play(tassel.current, [0, -12, 5, 0].map(rotate), { duration: 600, easing: 'ease-out' });
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
return (React.createElement("span", { ...rootProps(props, `iob-ani-expert${props.active ? ' iob-ani-expert-on' : ''}`) },
|
|
39
|
+
React.createElement("svg", { viewBox: "0 0 24 24" },
|
|
40
|
+
React.createElement("g", { ref: hat, className: "iob-ani-expert-hat" },
|
|
41
|
+
React.createElement("path", { className: "iob-ani-expert-shape", d: "M12 3.5L22.5 8.5L12 13.5L1.5 8.5Z" }),
|
|
42
|
+
React.createElement("path", { className: "iob-ani-expert-shape", d: "M5.5 13.7L12 16.8L18.5 13.7V17.1C18.5 19 15.6 20.5 12 20.5S5.5 19 5.5 17.1Z" }),
|
|
43
|
+
React.createElement("g", { ref: tassel, className: "iob-ani-expert-tassel" },
|
|
44
|
+
React.createElement("path", { className: "iob-ani-expert-cord", d: "M21.2 9.1V15.2" }),
|
|
45
|
+
React.createElement("path", { className: "iob-ani-expert-tuft", d: "M21.2 14.6L22.45 18.4H19.95Z" }))))));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=IconExpertMode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconExpertMode.js","sourceRoot":"./src/","sources":["Components/AnimatedIcons/IconExpertMode.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAA0B,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErG,MAAM,MAAM,GAAG,CAAC,GAAW,EAAY,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,GAAG,MAAM,EAAE,CAAC,CAAC;AAO/E;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,KAA0B;IACrD,qBAAqB,EAAE,CAAC;IACxB,MAAM,GAAG,GAAG,MAAM,CAAc,IAAI,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,CAAc,IAAI,CAAC,CAAC;IAEzC,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;QAC7B,IAAI,MAAM,EAAE,CAAC;YACT,IAAI,CACA,GAAG,CAAC,OAAO,EACX;gBACI,EAAE,SAAS,EAAE,4BAA4B,EAAE;gBAC3C,EAAE,SAAS,EAAE,mCAAmC,EAAE,MAAM,EAAE,IAAI,EAAE;gBAChE,EAAE,SAAS,EAAE,gCAAgC,EAAE,MAAM,EAAE,IAAI,EAAE;gBAC7D,EAAE,SAAS,EAAE,4BAA4B,EAAE;aAC9C,EACD,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,CACxC,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QACrG,CAAC;aAAM,CAAC;YACJ,IAAI,CACA,GAAG,CAAC,OAAO,EACX,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,EAAE,EAAE,SAAS,EAAE,mBAAmB,EAAE,EAAE,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,EACpG,EAAE,QAAQ,EAAE,GAAG,EAAE,CACpB,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QAC5F,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,CACH,iCAAU,SAAS,CAAC,KAAK,EAAE,iBAAiB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACnF,6BAAK,OAAO,EAAC,WAAW;YACpB,2BACI,GAAG,EAAE,GAAG,EACR,SAAS,EAAC,oBAAoB;gBAE9B,8BACI,SAAS,EAAC,sBAAsB,EAChC,CAAC,EAAC,mCAAmC,GACvC;gBACF,8BACI,SAAS,EAAC,sBAAsB,EAChC,CAAC,EAAC,6EAA6E,GACjF;gBACF,2BACI,GAAG,EAAE,MAAM,EACX,SAAS,EAAC,uBAAuB;oBAEjC,8BACI,SAAS,EAAC,qBAAqB,EAC/B,CAAC,EAAC,gBAAgB,GACpB;oBACF,8BACI,SAAS,EAAC,qBAAqB,EAC/B,CAAC,EAAC,8BAA8B,GAClC,CACF,CACJ,CACF,CACH,CACV,CAAC;AACN,CAAC","sourcesContent":["/**\n * Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>\n *\n * MIT License\n */\nimport React, { useRef } from 'react';\nimport { type AnimatedIconProps, play, rootProps, useAnimatedIconStyles, useChange } from './common';\n\nconst rotate = (deg: number): Keyframe => ({ transform: `rotate(${deg}deg)` });\n\nexport interface IconExpertModeProps extends AnimatedIconProps {\n /** The expert mode is on: the hat is filled. Switching it on lets the hat fly up. */\n active: boolean;\n}\n\n/**\n * Expert mode symbol: a mortarboard. Off it is only outlined, on it is filled, so both states differ also\n * without color. When the expert mode is switched on, the hat flies up a little and the tassel swings.\n *\n * ```tsx\n * <IconButton onClick={() => this.toggleExpertMode()}>\n * <IconExpertMode active={this.state.expertMode} />\n * </IconButton>\n * ```\n */\nexport function IconExpertMode(props: IconExpertModeProps): React.JSX.Element {\n useAnimatedIconStyles();\n const hat = useRef<SVGGElement>(null);\n const tassel = useRef<SVGGElement>(null);\n\n useChange(props.active, active => {\n if (active) {\n play(\n hat.current,\n [\n { transform: 'translateY(0) rotate(0deg)' },\n { transform: 'translateY(-3.5px) rotate(-10deg)', offset: 0.38 },\n { transform: 'translateY(0.6px) rotate(2deg)', offset: 0.72 },\n { transform: 'translateY(0) rotate(0deg)' },\n ],\n { duration: 700, easing: 'ease-out' },\n );\n play(tassel.current, [0, -40, 16, -8, 3, 0].map(rotate), { duration: 1100, easing: 'ease-out' });\n } else {\n play(\n hat.current,\n [{ transform: 'translateY(0)' }, { transform: 'translateY(0.8px)' }, { transform: 'translateY(0)' }],\n { duration: 260 },\n );\n play(tassel.current, [0, -12, 5, 0].map(rotate), { duration: 600, easing: 'ease-out' });\n }\n });\n\n return (\n <span {...rootProps(props, `iob-ani-expert${props.active ? ' iob-ani-expert-on' : ''}`)}>\n <svg viewBox=\"0 0 24 24\">\n <g\n ref={hat}\n className=\"iob-ani-expert-hat\"\n >\n <path\n className=\"iob-ani-expert-shape\"\n d=\"M12 3.5L22.5 8.5L12 13.5L1.5 8.5Z\"\n />\n <path\n className=\"iob-ani-expert-shape\"\n d=\"M5.5 13.7L12 16.8L18.5 13.7V17.1C18.5 19 15.6 20.5 12 20.5S5.5 19 5.5 17.1Z\"\n />\n <g\n ref={tassel}\n className=\"iob-ani-expert-tassel\"\n >\n <path\n className=\"iob-ani-expert-cord\"\n d=\"M21.2 9.1V15.2\"\n />\n <path\n className=\"iob-ani-expert-tuft\"\n d=\"M21.2 14.6L22.45 18.4H19.95Z\"\n />\n </g>\n </g>\n </svg>\n </span>\n );\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
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 IconFolderProps extends AnimatedIconProps {
|
|
9
|
+
/** The folder is open: its front flap folds down */
|
|
10
|
+
open: boolean;
|
|
11
|
+
/** Click on the icon, e.g. to open or close the folder */
|
|
12
|
+
onClick?: (e: React.MouseEvent<HTMLSpanElement>) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Folder that opens and closes: the front flap folds down and back up. In both end states it looks
|
|
16
|
+
* like `IconClosed` and `IconOpen`.
|
|
17
|
+
*
|
|
18
|
+
* ```tsx
|
|
19
|
+
* <IconFolder open={expanded} onClick={() => toggle(id)} />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function IconFolder(props: IconFolderProps): React.JSX.Element;
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
// The shapes of `IconClosed` and `IconOpen` (Font Awesome, regular): the closed folder, and the open one
|
|
9
|
+
// split into its back with the tab and its front flap
|
|
10
|
+
const CLOSED = 'M524,128 l-192,0 l-64,-64 l-160,0 c-26.51,0 -48,21.49 -48,48 l0,288 c0,26.51 21.49,48 48,48 l416,0 c26.51,0 48,-21.49 48,-48 l0,-224 c0,-26.51 -21.49,-48 -48,-48 z';
|
|
11
|
+
const BACK = 'M211.062,224 l328,0 l0,-48 c0,-26.51 -21.49,-48 -48,-48 l-160,0 l-64,-64 l-160,0 c-26.51,0 -48,21.49 -48,48 l0,278.046 l69.077,-118.418 c17.137,-29.378 48.912,-47.628 82.923,-47.628 z';
|
|
12
|
+
const FRONT = 'M631.756,292.093 l-72.424,124.155 a63.997,63.997 0 0 1 -55.281,31.752 l-399.964,0 c-18.523,0 -30.064,-20.093 -20.731,-36.093 l72.424,-124.155 a64,64 0 0 1 55.282,-31.752 l399.964,0 c18.523,0 30.064,20.093 20.73,36.093 z';
|
|
13
|
+
/**
|
|
14
|
+
* Folder that opens and closes: the front flap folds down and back up. In both end states it looks
|
|
15
|
+
* like `IconClosed` and `IconOpen`.
|
|
16
|
+
*
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <IconFolder open={expanded} onClick={() => toggle(id)} />
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function IconFolder(props) {
|
|
22
|
+
useAnimatedIconStyles();
|
|
23
|
+
return (React.createElement("span", { ...rootProps(props, `iob-ani-folder${props.open ? ' iob-ani-folder-open' : ''}`), onClick: props.onClick },
|
|
24
|
+
React.createElement("svg", { viewBox: "0 0 650 512" },
|
|
25
|
+
React.createElement("path", { d: BACK }),
|
|
26
|
+
React.createElement("path", { className: "iob-ani-folder-front", d: FRONT }),
|
|
27
|
+
React.createElement("path", { className: "iob-ani-folder-closed", d: CLOSED }))));
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=IconFolder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconFolder.js","sourceRoot":"./src/","sources":["Components/AnimatedIcons/IconFolder.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAA0B,SAAS,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEpF,yGAAyG;AACzG,sDAAsD;AACtD,MAAM,MAAM,GACR,qKAAqK,CAAC;AAC1K,MAAM,IAAI,GACN,yLAAyL,CAAC;AAC9L,MAAM,KAAK,GACP,6NAA6N,CAAC;AASlO;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC7C,qBAAqB,EAAE,CAAC;IACxB,OAAO,CACH,iCACQ,SAAS,CAAC,KAAK,EAAE,iBAAiB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EACjF,OAAO,EAAE,KAAK,CAAC,OAAO;QAEtB,6BAAK,OAAO,EAAC,aAAa;YACtB,8BAAM,CAAC,EAAE,IAAI,GAAI;YACjB,8BACI,SAAS,EAAC,sBAAsB,EAChC,CAAC,EAAE,KAAK,GACV;YACF,8BACI,SAAS,EAAC,uBAAuB,EACjC,CAAC,EAAE,MAAM,GACX,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\n// The shapes of `IconClosed` and `IconOpen` (Font Awesome, regular): the closed folder, and the open one\n// split into its back with the tab and its front flap\nconst CLOSED =\n 'M524,128 l-192,0 l-64,-64 l-160,0 c-26.51,0 -48,21.49 -48,48 l0,288 c0,26.51 21.49,48 48,48 l416,0 c26.51,0 48,-21.49 48,-48 l0,-224 c0,-26.51 -21.49,-48 -48,-48 z';\nconst BACK =\n 'M211.062,224 l328,0 l0,-48 c0,-26.51 -21.49,-48 -48,-48 l-160,0 l-64,-64 l-160,0 c-26.51,0 -48,21.49 -48,48 l0,278.046 l69.077,-118.418 c17.137,-29.378 48.912,-47.628 82.923,-47.628 z';\nconst FRONT =\n 'M631.756,292.093 l-72.424,124.155 a63.997,63.997 0 0 1 -55.281,31.752 l-399.964,0 c-18.523,0 -30.064,-20.093 -20.731,-36.093 l72.424,-124.155 a64,64 0 0 1 55.282,-31.752 l399.964,0 c18.523,0 30.064,20.093 20.73,36.093 z';\n\nexport interface IconFolderProps extends AnimatedIconProps {\n /** The folder is open: its front flap folds down */\n open: boolean;\n /** Click on the icon, e.g. to open or close the folder */\n onClick?: (e: React.MouseEvent<HTMLSpanElement>) => void;\n}\n\n/**\n * Folder that opens and closes: the front flap folds down and back up. In both end states it looks\n * like `IconClosed` and `IconOpen`.\n *\n * ```tsx\n * <IconFolder open={expanded} onClick={() => toggle(id)} />\n * ```\n */\nexport function IconFolder(props: IconFolderProps): React.JSX.Element {\n useAnimatedIconStyles();\n return (\n <span\n {...rootProps(props, `iob-ani-folder${props.open ? ' iob-ani-folder-open' : ''}`)}\n onClick={props.onClick}\n >\n <svg viewBox=\"0 0 650 512\">\n <path d={BACK} />\n <path\n className=\"iob-ani-folder-front\"\n d={FRONT}\n />\n <path\n className=\"iob-ani-folder-closed\"\n d={CLOSED}\n />\n </svg>\n </span>\n );\n}\n"]}
|
|
@@ -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 { type AnimatedIconProps } from './common';
|
|
8
|
+
export interface IconMenuArrowProps extends AnimatedIconProps {
|
|
9
|
+
/** false: menu symbol (three bars), true: arrow */
|
|
10
|
+
open: boolean;
|
|
11
|
+
/** Direction of the arrow (default: left, e.g. to collapse a menu on the left side) */
|
|
12
|
+
direction?: 'left' | 'right';
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Menu symbol that turns into an arrow, e.g. for the button that opens and closes the side menu.
|
|
16
|
+
*
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <IconButton onClick={() => this.toggleDrawer()}>
|
|
19
|
+
* <IconMenuArrow open={this.state.drawerOpen} />
|
|
20
|
+
* </IconButton>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function IconMenuArrow(props: IconMenuArrowProps): React.JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
* Menu symbol that turns into an arrow, e.g. for the button that opens and closes the side menu.
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <IconButton onClick={() => this.toggleDrawer()}>
|
|
13
|
+
* <IconMenuArrow open={this.state.drawerOpen} />
|
|
14
|
+
* </IconButton>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function IconMenuArrow(props) {
|
|
18
|
+
useAnimatedIconStyles();
|
|
19
|
+
return (React.createElement("span", { ...rootProps(props, `iob-ani-menu${props.open ? ' iob-ani-menu-open' : ''}${props.direction === 'right' ? ' iob-ani-menu-right' : ''}`) },
|
|
20
|
+
React.createElement("span", { className: "iob-ani-layer iob-ani-menu-rot" },
|
|
21
|
+
React.createElement("span", { className: "iob-ani-layer iob-ani-menu-flip" },
|
|
22
|
+
React.createElement("span", { className: "iob-ani-menu-bar iob-ani-menu-b1" }),
|
|
23
|
+
React.createElement("span", { className: "iob-ani-menu-bar iob-ani-menu-b2" }),
|
|
24
|
+
React.createElement("span", { className: "iob-ani-menu-bar iob-ani-menu-b3" })))));
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=IconMenuArrow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconMenuArrow.js","sourceRoot":"./src/","sources":["Components/AnimatedIcons/IconMenuArrow.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAA0B,SAAS,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AASpF;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB;IACnD,qBAAqB,EAAE,CAAC;IACxB,OAAO,CACH,iCACQ,SAAS,CACT,KAAK,EACL,eAAe,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CACrH;QAED,8BAAM,SAAS,EAAC,gCAAgC;YAC5C,8BAAM,SAAS,EAAC,iCAAiC;gBAC7C,8BAAM,SAAS,EAAC,kCAAkC,GAAG;gBACrD,8BAAM,SAAS,EAAC,kCAAkC,GAAG;gBACrD,8BAAM,SAAS,EAAC,kCAAkC,GAAG,CAClD,CACJ,CACJ,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 IconMenuArrowProps extends AnimatedIconProps {\n /** false: menu symbol (three bars), true: arrow */\n open: boolean;\n /** Direction of the arrow (default: left, e.g. to collapse a menu on the left side) */\n direction?: 'left' | 'right';\n}\n\n/**\n * Menu symbol that turns into an arrow, e.g. for the button that opens and closes the side menu.\n *\n * ```tsx\n * <IconButton onClick={() => this.toggleDrawer()}>\n * <IconMenuArrow open={this.state.drawerOpen} />\n * </IconButton>\n * ```\n */\nexport function IconMenuArrow(props: IconMenuArrowProps): React.JSX.Element {\n useAnimatedIconStyles();\n return (\n <span\n {...rootProps(\n props,\n `iob-ani-menu${props.open ? ' iob-ani-menu-open' : ''}${props.direction === 'right' ? ' iob-ani-menu-right' : ''}`,\n )}\n >\n <span className=\"iob-ani-layer iob-ani-menu-rot\">\n <span className=\"iob-ani-layer iob-ani-menu-flip\">\n <span className=\"iob-ani-menu-bar iob-ani-menu-b1\" />\n <span className=\"iob-ani-menu-bar iob-ani-menu-b2\" />\n <span className=\"iob-ani-menu-bar iob-ani-menu-b3\" />\n </span>\n </span>\n </span>\n );\n}\n"]}
|
|
@@ -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 { type AnimatedIconProps } from './common';
|
|
8
|
+
export interface IconPlayPauseProps extends AnimatedIconProps {
|
|
9
|
+
/** true: the pause symbol (it runs and can be paused or stopped), false: the play symbol */
|
|
10
|
+
running: boolean;
|
|
11
|
+
/** Waiting for the result of the click, e.g. until the instance really started: a ring turns around the symbol */
|
|
12
|
+
pending?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Play and pause symbol that turns into each other.
|
|
16
|
+
*
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <IconButton onClick={...}>
|
|
19
|
+
* <IconPlayPause running={instance.running} pending={instance.starting} />
|
|
20
|
+
* </IconButton>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function IconPlayPause(props: IconPlayPauseProps): React.JSX.Element;
|
|
@@ -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 { rootProps, useAnimatedIconStyles } from './common';
|
|
8
|
+
/**
|
|
9
|
+
* Play and pause symbol that turns into each other.
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <IconButton onClick={...}>
|
|
13
|
+
* <IconPlayPause running={instance.running} pending={instance.starting} />
|
|
14
|
+
* </IconButton>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function IconPlayPause(props) {
|
|
18
|
+
useAnimatedIconStyles();
|
|
19
|
+
return (React.createElement("span", { ...rootProps(props, `iob-ani-pp${props.running ? ' iob-ani-on' : ''}${props.pending ? ' iob-ani-pp-pending' : ''}`) },
|
|
20
|
+
React.createElement("span", { className: "iob-ani-pp-a" }),
|
|
21
|
+
React.createElement("span", { className: "iob-ani-pp-b" }),
|
|
22
|
+
React.createElement("svg", { className: "iob-ani-pp-ring", viewBox: "0 0 24 24" },
|
|
23
|
+
React.createElement("circle", { cx: "12", cy: "12", r: "11", pathLength: 1 }))));
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=IconPlayPause.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconPlayPause.js","sourceRoot":"./src/","sources":["Components/AnimatedIcons/IconPlayPause.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAA0B,SAAS,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AASpF;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB;IACnD,qBAAqB,EAAE,CAAC;IACxB,OAAO,CACH,iCACQ,SAAS,CACT,KAAK,EACL,aAAa,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CACjG;QAED,8BAAM,SAAS,EAAC,cAAc,GAAG;QACjC,8BAAM,SAAS,EAAC,cAAc,GAAG;QACjC,6BACI,SAAS,EAAC,iBAAiB,EAC3B,OAAO,EAAC,WAAW;YAEnB,gCACI,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAC,IAAI,EACN,UAAU,EAAE,CAAC,GACf,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 IconPlayPauseProps extends AnimatedIconProps {\n /** true: the pause symbol (it runs and can be paused or stopped), false: the play symbol */\n running: boolean;\n /** Waiting for the result of the click, e.g. until the instance really started: a ring turns around the symbol */\n pending?: boolean;\n}\n\n/**\n * Play and pause symbol that turns into each other.\n *\n * ```tsx\n * <IconButton onClick={...}>\n * <IconPlayPause running={instance.running} pending={instance.starting} />\n * </IconButton>\n * ```\n */\nexport function IconPlayPause(props: IconPlayPauseProps): React.JSX.Element {\n useAnimatedIconStyles();\n return (\n <span\n {...rootProps(\n props,\n `iob-ani-pp${props.running ? ' iob-ani-on' : ''}${props.pending ? ' iob-ani-pp-pending' : ''}`,\n )}\n >\n <span className=\"iob-ani-pp-a\" />\n <span className=\"iob-ani-pp-b\" />\n <svg\n className=\"iob-ani-pp-ring\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"11\"\n pathLength={1}\n />\n </svg>\n </span>\n );\n}\n"]}
|
|
@@ -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 { type AnimatedIconProps } from './common';
|
|
8
|
+
export interface IconRefreshProps extends AnimatedIconProps {
|
|
9
|
+
/** Turns while true. When it becomes false, the turn ends smoothly. */
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
/** After loading, a check mark appears for a moment (default: true) */
|
|
12
|
+
showDone?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Refresh symbol for reload buttons. It turns while the data loads and confirms the end with a check mark.
|
|
16
|
+
*
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <IconButton onClick={() => this.reload()} disabled={this.state.loading}>
|
|
19
|
+
* <IconRefresh loading={this.state.loading} />
|
|
20
|
+
* </IconButton>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function IconRefresh(props: IconRefreshProps): React.JSX.Element;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*/
|
|
6
|
+
import React, { useEffect, useRef } from 'react';
|
|
7
|
+
import { play, prefersReducedMotion, rootProps, useAnimatedIconStyles } from './common';
|
|
8
|
+
const TURN = 900;
|
|
9
|
+
/**
|
|
10
|
+
* Refresh symbol for reload buttons. It turns while the data loads and confirms the end with a check mark.
|
|
11
|
+
*
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <IconButton onClick={() => this.reload()} disabled={this.state.loading}>
|
|
14
|
+
* <IconRefresh loading={this.state.loading} />
|
|
15
|
+
* </IconButton>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function IconRefresh(props) {
|
|
19
|
+
useAnimatedIconStyles();
|
|
20
|
+
const spin = useRef(null);
|
|
21
|
+
const check = useRef(null);
|
|
22
|
+
const animations = useRef([]);
|
|
23
|
+
const turning = useRef(null);
|
|
24
|
+
const { loading } = props;
|
|
25
|
+
const showDone = props.showDone !== false;
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const element = spin.current;
|
|
28
|
+
if (!element?.animate) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (loading) {
|
|
32
|
+
animations.current.forEach(a => a?.cancel());
|
|
33
|
+
animations.current = [];
|
|
34
|
+
turning.current = prefersReducedMotion()
|
|
35
|
+
? element.animate([{ opacity: 1 }, { opacity: 0.4 }, { opacity: 1 }], {
|
|
36
|
+
duration: 1200,
|
|
37
|
+
iterations: Infinity,
|
|
38
|
+
})
|
|
39
|
+
: element.animate([{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }], {
|
|
40
|
+
duration: TURN,
|
|
41
|
+
iterations: Infinity,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else if (turning.current) {
|
|
45
|
+
// finish the current turn instead of jumping back to 0 degrees
|
|
46
|
+
const time = Number(turning.current.currentTime) || 0;
|
|
47
|
+
const angle = ((time % TURN) / TURN) * 360;
|
|
48
|
+
turning.current.cancel();
|
|
49
|
+
turning.current = null;
|
|
50
|
+
const rest = 250 + ((360 - angle) / 360) * 350;
|
|
51
|
+
animations.current.push(play(element, [{ transform: `rotate(${angle}deg)` }, { transform: 'rotate(360deg)' }], {
|
|
52
|
+
duration: rest,
|
|
53
|
+
easing: 'cubic-bezier(0.2, 0.8, 0.3, 1)',
|
|
54
|
+
}));
|
|
55
|
+
if (showDone) {
|
|
56
|
+
animations.current.push(play(element, [
|
|
57
|
+
{ opacity: 1, transform: 'scale(1)' },
|
|
58
|
+
{ opacity: 0, transform: 'scale(0.6)', offset: 0.12 },
|
|
59
|
+
{ opacity: 0, transform: 'scale(0.6)', offset: 0.85 },
|
|
60
|
+
{ opacity: 1, transform: 'scale(1)' },
|
|
61
|
+
], { duration: 1500, delay: rest }));
|
|
62
|
+
animations.current.push(play(check.current, [{ opacity: 0 }, { opacity: 1, offset: 0.1 }, { opacity: 1, offset: 0.85 }, { opacity: 0 }], {
|
|
63
|
+
duration: 1500,
|
|
64
|
+
delay: rest,
|
|
65
|
+
}));
|
|
66
|
+
animations.current.push(play(check.current?.querySelector('path'), [
|
|
67
|
+
{ strokeDashoffset: 1 },
|
|
68
|
+
{ strokeDashoffset: 1, offset: 0.1 },
|
|
69
|
+
{ strokeDashoffset: 0, offset: 0.35 },
|
|
70
|
+
{ strokeDashoffset: 0 },
|
|
71
|
+
], { duration: 1500, delay: rest }));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}, [loading, showDone]);
|
|
75
|
+
useEffect(() => () => {
|
|
76
|
+
turning.current?.cancel();
|
|
77
|
+
animations.current.forEach(a => a?.cancel());
|
|
78
|
+
}, []);
|
|
79
|
+
return (React.createElement("span", { ...rootProps(props, 'iob-ani-rf') },
|
|
80
|
+
React.createElement("span", { className: "iob-ani-layer", ref: spin },
|
|
81
|
+
React.createElement("svg", { viewBox: "0 0 24 24", width: "100%", height: "100%" },
|
|
82
|
+
React.createElement("path", { fill: "currentColor", d: "M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" }))),
|
|
83
|
+
React.createElement("svg", { className: "iob-ani-rf-done", viewBox: "0 0 24 24", ref: check },
|
|
84
|
+
React.createElement("path", { d: "M5.5 12.5l4.5 4.5 8.5-9", pathLength: 1 }))));
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=IconRefresh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconRefresh.js","sourceRoot":"./src/","sources":["Components/AnimatedIcons/IconRefresh.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * Copyright 2026 Denis Haev (bluefox) <dogafox@gmail.com>\n *\n * MIT License\n */\nimport React, { useEffect, useRef } from 'react';\nimport { type AnimatedIconProps, play, prefersReducedMotion, rootProps, useAnimatedIconStyles } from './common';\n\nconst TURN = 900;\n\nexport interface IconRefreshProps extends AnimatedIconProps {\n /** Turns while true. When it becomes false, the turn ends smoothly. */\n loading?: boolean;\n /** After loading, a check mark appears for a moment (default: true) */\n showDone?: boolean;\n}\n\n/**\n * Refresh symbol for reload buttons. It turns while the data loads and confirms the end with a check mark.\n *\n * ```tsx\n * <IconButton onClick={() => this.reload()} disabled={this.state.loading}>\n * <IconRefresh loading={this.state.loading} />\n * </IconButton>\n * ```\n */\nexport function IconRefresh(props: IconRefreshProps): React.JSX.Element {\n useAnimatedIconStyles();\n const spin = useRef<HTMLSpanElement>(null);\n const check = useRef<SVGSVGElement>(null);\n const animations = useRef<(Animation | null)[]>([]);\n const turning = useRef<Animation | null>(null);\n const { loading } = props;\n const showDone = props.showDone !== false;\n\n useEffect(() => {\n const element = spin.current;\n if (!element?.animate) {\n return;\n }\n if (loading) {\n animations.current.forEach(a => a?.cancel());\n animations.current = [];\n turning.current = prefersReducedMotion()\n ? element.animate([{ opacity: 1 }, { opacity: 0.4 }, { opacity: 1 }], {\n duration: 1200,\n iterations: Infinity,\n })\n : element.animate([{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }], {\n duration: TURN,\n iterations: Infinity,\n });\n } else if (turning.current) {\n // finish the current turn instead of jumping back to 0 degrees\n const time = Number(turning.current.currentTime) || 0;\n const angle = ((time % TURN) / TURN) * 360;\n turning.current.cancel();\n turning.current = null;\n const rest = 250 + ((360 - angle) / 360) * 350;\n animations.current.push(\n play(element, [{ transform: `rotate(${angle}deg)` }, { transform: 'rotate(360deg)' }], {\n duration: rest,\n easing: 'cubic-bezier(0.2, 0.8, 0.3, 1)',\n }),\n );\n if (showDone) {\n animations.current.push(\n play(\n element,\n [\n { opacity: 1, transform: 'scale(1)' },\n { opacity: 0, transform: 'scale(0.6)', offset: 0.12 },\n { opacity: 0, transform: 'scale(0.6)', offset: 0.85 },\n { opacity: 1, transform: 'scale(1)' },\n ],\n { duration: 1500, delay: rest },\n ),\n );\n animations.current.push(\n play(\n check.current,\n [{ opacity: 0 }, { opacity: 1, offset: 0.1 }, { opacity: 1, offset: 0.85 }, { opacity: 0 }],\n {\n duration: 1500,\n delay: rest,\n },\n ),\n );\n animations.current.push(\n play(\n check.current?.querySelector('path'),\n [\n { strokeDashoffset: 1 },\n { strokeDashoffset: 1, offset: 0.1 },\n { strokeDashoffset: 0, offset: 0.35 },\n { strokeDashoffset: 0 },\n ],\n { duration: 1500, delay: rest },\n ),\n );\n }\n }\n }, [loading, showDone]);\n\n useEffect(\n () => () => {\n turning.current?.cancel();\n animations.current.forEach(a => a?.cancel());\n },\n [],\n );\n\n return (\n <span {...rootProps(props, 'iob-ani-rf')}>\n <span\n className=\"iob-ani-layer\"\n ref={spin}\n >\n <svg\n viewBox=\"0 0 24 24\"\n width=\"100%\"\n height=\"100%\"\n >\n <path\n fill=\"currentColor\"\n d=\"M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\"\n />\n </svg>\n </span>\n <svg\n className=\"iob-ani-rf-done\"\n viewBox=\"0 0 24 24\"\n ref={check}\n >\n <path\n d=\"M5.5 12.5l4.5 4.5 8.5-9\"\n pathLength={1}\n />\n </svg>\n </span>\n );\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
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 IconResultProps extends AnimatedIconProps {
|
|
9
|
+
/** success: check mark (green), warning: exclamation mark (orange), error: cross (red). The color can be changed with `style.color`. */
|
|
10
|
+
type: 'success' | 'warning' | 'error';
|
|
11
|
+
/** Every change of this value draws the icon again, e.g. a counter of the save clicks */
|
|
12
|
+
replay?: string | number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Result of an action: a circle and the mark draw themselves, a warning or an error shakes once.
|
|
16
|
+
*
|
|
17
|
+
* ```tsx
|
|
18
|
+
* {saved ? <IconResult type="success" replay={saveCount} /> : null}
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function IconResult(props: IconResultProps): React.JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
* Result of an action: a circle and the mark draw themselves, a warning or an error shakes once.
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* {saved ? <IconResult type="success" replay={saveCount} /> : null}
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function IconResult(props) {
|
|
16
|
+
useAnimatedIconStyles();
|
|
17
|
+
let mark;
|
|
18
|
+
if (props.type === 'success') {
|
|
19
|
+
mark = (React.createElement("path", { className: "iob-ani-res-mark", d: "M7.5 12.5l3 3 6-6.5", pathLength: 1 }));
|
|
20
|
+
}
|
|
21
|
+
else if (props.type === 'warning') {
|
|
22
|
+
mark = (React.createElement(React.Fragment, null,
|
|
23
|
+
React.createElement("path", { className: "iob-ani-res-mark", d: "M12 7.5v5", pathLength: 1 }),
|
|
24
|
+
React.createElement("path", { className: "iob-ani-res-mark2", d: "M12 16.4v.1", pathLength: 1 })));
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
mark = (React.createElement(React.Fragment, null,
|
|
28
|
+
React.createElement("path", { className: "iob-ani-res-mark", d: "M8.7 8.7l6.6 6.6", pathLength: 1 }),
|
|
29
|
+
React.createElement("path", { className: "iob-ani-res-mark2", d: "M15.3 8.7l-6.6 6.6", pathLength: 1 })));
|
|
30
|
+
}
|
|
31
|
+
return (React.createElement("span", { ...rootProps(props, `iob-ani-res iob-ani-res-${props.type}`) },
|
|
32
|
+
React.createElement("svg", { key: `${props.type}-${props.replay ?? ''}`, viewBox: "0 0 24 24" },
|
|
33
|
+
React.createElement("circle", { className: "iob-ani-res-circle", cx: "12", cy: "12", r: "10", pathLength: 1 }),
|
|
34
|
+
mark)));
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=IconResult.js.map
|