@iobroker/dm-gui-components 10.0.20 → 10.0.22
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 +12 -0
- package/build/DeviceCard.d.ts +46 -45
- package/build/DeviceCard.js +130 -163
- package/build/DeviceCard.js.map +1 -1
- package/build/DeviceFields.d.ts +75 -0
- package/build/DeviceFields.js +190 -0
- package/build/DeviceFields.js.map +1 -0
- package/build/DeviceList.d.ts +59 -7
- package/build/DeviceList.js +260 -87
- package/build/DeviceList.js.map +1 -1
- package/build/InstanceActionButton.js +3 -1
- package/build/InstanceActionButton.js.map +1 -1
- package/build/LazyRender.d.ts +69 -0
- package/build/LazyRender.js +128 -0
- package/build/LazyRender.js.map +1 -0
- package/build/StateOrObjectHandler.d.ts +3 -0
- package/build/StateOrObjectHandler.js +57 -7
- package/build/StateOrObjectHandler.js.map +1 -1
- package/build/TooltipButton.d.ts +2 -0
- package/build/TooltipButton.js +2 -2
- package/build/TooltipButton.js.map +1 -1
- package/build/Utils.d.ts +7 -0
- package/build/Utils.js +13 -0
- package/build/Utils.js.map +1 -1
- package/build/hooks.js +22 -3
- package/build/hooks.js.map +1 -1
- package/build/i18n/de.json +1 -0
- package/build/i18n/en.json +1 -0
- package/build/i18n/es.json +1 -0
- package/build/i18n/fr.json +1 -0
- package/build/i18n/it.json +1 -0
- package/build/i18n/nl.json +1 -0
- package/build/i18n/pl.json +1 -0
- package/build/i18n/pt.json +1 -0
- package/build/i18n/ru.json +1 -0
- package/build/i18n/uk.json +1 -0
- package/build/i18n/zh-cn.json +1 -0
- package/package.json +16 -15
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* One `IntersectionObserver` for all cards of a list.
|
|
4
|
+
*
|
|
5
|
+
* A device manager with 100 devices would otherwise create 100 observers. The root is the scrolling
|
|
6
|
+
* container of the list; it is set as soon as the container is mounted, because the `rootMargin` of
|
|
7
|
+
* an observer that watches the viewport would be cut off by the clip rectangle of that container -
|
|
8
|
+
* the cards would then only be mounted once they are really visible, and the user would see them
|
|
9
|
+
* pop in.
|
|
10
|
+
*/
|
|
11
|
+
export class LazyRenderObserver {
|
|
12
|
+
observer = null;
|
|
13
|
+
root = null;
|
|
14
|
+
callbacks = new Map();
|
|
15
|
+
rootMargin;
|
|
16
|
+
/** Browsers without `IntersectionObserver` simply render everything */
|
|
17
|
+
supported = typeof IntersectionObserver !== 'undefined';
|
|
18
|
+
/**
|
|
19
|
+
* @param rootMargin how far outside the visible area a card is already rendered
|
|
20
|
+
*/
|
|
21
|
+
constructor(rootMargin = '900px 0px') {
|
|
22
|
+
this.rootMargin = rootMargin;
|
|
23
|
+
}
|
|
24
|
+
/** Set the scrolling container. Re-creates the observer and re-observes all known elements */
|
|
25
|
+
setRoot(root) {
|
|
26
|
+
if (!this.supported || root === this.root) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
this.root = root;
|
|
30
|
+
this.observer?.disconnect();
|
|
31
|
+
this.observer = null;
|
|
32
|
+
if (this.callbacks.size) {
|
|
33
|
+
const observer = this.getObserver();
|
|
34
|
+
for (const element of this.callbacks.keys()) {
|
|
35
|
+
observer.observe(element);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
observe(element, callback) {
|
|
40
|
+
if (!this.supported) {
|
|
41
|
+
callback(true);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
this.callbacks.set(element, callback);
|
|
45
|
+
this.getObserver().observe(element);
|
|
46
|
+
}
|
|
47
|
+
unobserve(element) {
|
|
48
|
+
this.callbacks.delete(element);
|
|
49
|
+
this.observer?.unobserve(element);
|
|
50
|
+
}
|
|
51
|
+
destroy() {
|
|
52
|
+
this.observer?.disconnect();
|
|
53
|
+
this.observer = null;
|
|
54
|
+
this.callbacks.clear();
|
|
55
|
+
}
|
|
56
|
+
getObserver() {
|
|
57
|
+
this.observer ||= new IntersectionObserver(this.handleEntries, {
|
|
58
|
+
root: this.root,
|
|
59
|
+
rootMargin: this.rootMargin,
|
|
60
|
+
});
|
|
61
|
+
return this.observer;
|
|
62
|
+
}
|
|
63
|
+
handleEntries = (entries) => {
|
|
64
|
+
for (const entry of entries) {
|
|
65
|
+
this.callbacks.get(entry.target)?.(entry.isIntersecting);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Renders its content only while it is inside or near the visible area of the list.
|
|
71
|
+
*
|
|
72
|
+
* The placeholder always occupies the full footprint of a card, so the layout of the wrapping
|
|
73
|
+
* flex container and the length of the scrollbar stay exactly the same as with all cards rendered.
|
|
74
|
+
*/
|
|
75
|
+
export class LazyRender extends React.Component {
|
|
76
|
+
ref = React.createRef();
|
|
77
|
+
/**
|
|
78
|
+
* Height of the content the last time it was rendered. A card can be higher than `minHeight`
|
|
79
|
+
* (custom info, several status lines), and without this the list below would jump as soon as
|
|
80
|
+
* such a card is unmounted while scrolling.
|
|
81
|
+
*/
|
|
82
|
+
lastHeight = 0;
|
|
83
|
+
/**
|
|
84
|
+
* Synchronous mirror of `state.visible`. Two observer callbacks can arrive before `setState` is
|
|
85
|
+
* committed, and the second one must not be swallowed by a comparison against a stale state.
|
|
86
|
+
*/
|
|
87
|
+
visible;
|
|
88
|
+
constructor(props) {
|
|
89
|
+
super(props);
|
|
90
|
+
this.visible = !props.observer.supported;
|
|
91
|
+
this.state = { visible: this.visible };
|
|
92
|
+
}
|
|
93
|
+
componentDidMount() {
|
|
94
|
+
if (this.ref.current) {
|
|
95
|
+
this.props.observer.observe(this.ref.current, this.onVisibilityChanged);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
componentWillUnmount() {
|
|
99
|
+
if (this.ref.current) {
|
|
100
|
+
this.props.observer.unobserve(this.ref.current);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
onVisibilityChanged = (visible) => {
|
|
104
|
+
if (visible === this.visible) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!visible) {
|
|
108
|
+
this.lastHeight = this.ref.current?.getBoundingClientRect().height || this.lastHeight;
|
|
109
|
+
}
|
|
110
|
+
this.visible = visible;
|
|
111
|
+
this.setState({ visible });
|
|
112
|
+
};
|
|
113
|
+
render() {
|
|
114
|
+
return (React.createElement("div", { ref: this.ref, style: {
|
|
115
|
+
width: this.props.width,
|
|
116
|
+
// While the content is rendered, `minHeight` is the floor of a card. While it is
|
|
117
|
+
// not, the height of its last rendering is kept as well, so that the cards below
|
|
118
|
+
// do not jump when a higher card is dropped during scrolling.
|
|
119
|
+
minHeight: this.state.visible
|
|
120
|
+
? this.props.minHeight
|
|
121
|
+
: Math.max(this.props.minHeight, this.lastHeight),
|
|
122
|
+
margin: this.props.margin,
|
|
123
|
+
display: 'flex',
|
|
124
|
+
flexShrink: 0,
|
|
125
|
+
} }, this.state.visible ? this.props.children() : null));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=LazyRender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LazyRender.js","sourceRoot":"./src/","sources":["LazyRender.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { type JSX } from 'react';\n\ntype VisibilityCallback = (visible: boolean) => void;\n\n/**\n * One `IntersectionObserver` for all cards of a list.\n *\n * A device manager with 100 devices would otherwise create 100 observers. The root is the scrolling\n * container of the list; it is set as soon as the container is mounted, because the `rootMargin` of\n * an observer that watches the viewport would be cut off by the clip rectangle of that container -\n * the cards would then only be mounted once they are really visible, and the user would see them\n * pop in.\n */\nexport class LazyRenderObserver {\n private observer: IntersectionObserver | null = null;\n\n private root: Element | null = null;\n\n private readonly callbacks = new Map<Element, VisibilityCallback>();\n\n private readonly rootMargin: string;\n\n /** Browsers without `IntersectionObserver` simply render everything */\n public readonly supported: boolean = typeof IntersectionObserver !== 'undefined';\n\n /**\n * @param rootMargin how far outside the visible area a card is already rendered\n */\n constructor(rootMargin = '900px 0px') {\n this.rootMargin = rootMargin;\n }\n\n /** Set the scrolling container. Re-creates the observer and re-observes all known elements */\n public setRoot(root: Element | null): void {\n if (!this.supported || root === this.root) {\n return;\n }\n this.root = root;\n this.observer?.disconnect();\n this.observer = null;\n if (this.callbacks.size) {\n const observer = this.getObserver();\n for (const element of this.callbacks.keys()) {\n observer.observe(element);\n }\n }\n }\n\n public observe(element: Element, callback: VisibilityCallback): void {\n if (!this.supported) {\n callback(true);\n return;\n }\n this.callbacks.set(element, callback);\n this.getObserver().observe(element);\n }\n\n public unobserve(element: Element): void {\n this.callbacks.delete(element);\n this.observer?.unobserve(element);\n }\n\n public destroy(): void {\n this.observer?.disconnect();\n this.observer = null;\n this.callbacks.clear();\n }\n\n private getObserver(): IntersectionObserver {\n this.observer ||= new IntersectionObserver(this.handleEntries, {\n root: this.root,\n rootMargin: this.rootMargin,\n });\n return this.observer;\n }\n\n private handleEntries = (entries: IntersectionObserverEntry[]): void => {\n for (const entry of entries) {\n this.callbacks.get(entry.target)?.(entry.isIntersecting);\n }\n };\n}\n\ninterface LazyRenderProps {\n observer: LazyRenderObserver;\n /** Width of the placeholder while the content is not rendered */\n width: number;\n /** Height of the placeholder while the content was never rendered yet */\n minHeight: number;\n margin: number;\n /** Only called while the placeholder is inside (or near) the visible area of the list */\n children: () => JSX.Element;\n}\n\ninterface LazyRenderState {\n visible: boolean;\n}\n\n/**\n * Renders its content only while it is inside or near the visible area of the list.\n *\n * The placeholder always occupies the full footprint of a card, so the layout of the wrapping\n * flex container and the length of the scrollbar stay exactly the same as with all cards rendered.\n */\nexport class LazyRender extends React.Component<LazyRenderProps, LazyRenderState> {\n private readonly ref = React.createRef<HTMLDivElement>();\n\n /**\n * Height of the content the last time it was rendered. A card can be higher than `minHeight`\n * (custom info, several status lines), and without this the list below would jump as soon as\n * such a card is unmounted while scrolling.\n */\n private lastHeight = 0;\n\n /**\n * Synchronous mirror of `state.visible`. Two observer callbacks can arrive before `setState` is\n * committed, and the second one must not be swallowed by a comparison against a stale state.\n */\n private visible: boolean;\n\n constructor(props: LazyRenderProps) {\n super(props);\n this.visible = !props.observer.supported;\n this.state = { visible: this.visible };\n }\n\n componentDidMount(): void {\n if (this.ref.current) {\n this.props.observer.observe(this.ref.current, this.onVisibilityChanged);\n }\n }\n\n componentWillUnmount(): void {\n if (this.ref.current) {\n this.props.observer.unobserve(this.ref.current);\n }\n }\n\n private onVisibilityChanged = (visible: boolean): void => {\n if (visible === this.visible) {\n return;\n }\n if (!visible) {\n this.lastHeight = this.ref.current?.getBoundingClientRect().height || this.lastHeight;\n }\n this.visible = visible;\n this.setState({ visible });\n };\n\n render(): JSX.Element {\n return (\n <div\n ref={this.ref}\n style={{\n width: this.props.width,\n // While the content is rendered, `minHeight` is the floor of a card. While it is\n // not, the height of its last rendering is kept as well, so that the cards below\n // do not jump when a higher card is dropped during scrolling.\n minHeight: this.state.visible\n ? this.props.minHeight\n : Math.max(this.props.minHeight, this.lastHeight),\n margin: this.props.margin,\n display: 'flex',\n flexShrink: 0,\n }}\n >\n {this.state.visible ? this.props.children() : null}\n </div>\n );\n }\n}\n"]}
|
|
@@ -7,7 +7,10 @@ export declare class StateOrObjectHandler {
|
|
|
7
7
|
private readonly socket;
|
|
8
8
|
private readonly objectSubs;
|
|
9
9
|
private readonly stateSubs;
|
|
10
|
+
private destroyed;
|
|
10
11
|
constructor(socket: Connection);
|
|
12
|
+
/** Unsubscribe everything. To be called when the component owning this handler is unmounted */
|
|
13
|
+
destroy(): void;
|
|
11
14
|
addListener<T extends ioBroker.StringOrTranslated | number | boolean>(item: ValueOrStateOrObject<T> | undefined, callback: (value: T | undefined) => void): Promise<StateOrObjectSubscription>;
|
|
12
15
|
private addObjectListener;
|
|
13
16
|
private addStateListener;
|
|
@@ -1,13 +1,42 @@
|
|
|
1
1
|
const emptySubscription = {
|
|
2
2
|
unsubscribe: () => { },
|
|
3
3
|
};
|
|
4
|
+
/**
|
|
5
|
+
* How long a subscription without any listener is kept before it is really unsubscribed.
|
|
6
|
+
*
|
|
7
|
+
* The cards of the device list are mounted and unmounted while scrolling. Without this grace period
|
|
8
|
+
* every card that scrolls in and out again would cause a new `getObject`/`getState` round trip plus
|
|
9
|
+
* a new subscription on the socket.
|
|
10
|
+
*/
|
|
11
|
+
const UNSUBSCRIBE_GRACE_MS = 10_000;
|
|
4
12
|
export class StateOrObjectHandler {
|
|
5
13
|
socket;
|
|
6
14
|
objectSubs = new Map();
|
|
7
15
|
stateSubs = new Map();
|
|
16
|
+
destroyed = false;
|
|
8
17
|
constructor(socket) {
|
|
9
18
|
this.socket = socket;
|
|
10
19
|
}
|
|
20
|
+
/** Unsubscribe everything. To be called when the component owning this handler is unmounted */
|
|
21
|
+
destroy() {
|
|
22
|
+
this.destroyed = true;
|
|
23
|
+
for (const [objectId, sub] of this.objectSubs) {
|
|
24
|
+
if (sub.lingerTimer) {
|
|
25
|
+
clearTimeout(sub.lingerTimer);
|
|
26
|
+
}
|
|
27
|
+
sub.notifiers.length = 0;
|
|
28
|
+
void this.socket.unsubscribeObject(objectId, sub.handler);
|
|
29
|
+
}
|
|
30
|
+
this.objectSubs.clear();
|
|
31
|
+
for (const [stateId, sub] of this.stateSubs) {
|
|
32
|
+
if (sub.lingerTimer) {
|
|
33
|
+
clearTimeout(sub.lingerTimer);
|
|
34
|
+
}
|
|
35
|
+
sub.notifiers.length = 0;
|
|
36
|
+
this.socket.unsubscribeState(stateId, sub.handler);
|
|
37
|
+
}
|
|
38
|
+
this.stateSubs.clear();
|
|
39
|
+
}
|
|
11
40
|
async addListener(item, callback) {
|
|
12
41
|
if (item === undefined) {
|
|
13
42
|
callback(undefined);
|
|
@@ -54,6 +83,11 @@ export class StateOrObjectHandler {
|
|
|
54
83
|
};
|
|
55
84
|
const existing = this.objectSubs.get(objectId);
|
|
56
85
|
if (existing) {
|
|
86
|
+
if (existing.lingerTimer) {
|
|
87
|
+
// The subscription was about to be dropped - take it over instead
|
|
88
|
+
clearTimeout(existing.lingerTimer);
|
|
89
|
+
existing.lingerTimer = undefined;
|
|
90
|
+
}
|
|
57
91
|
existing.notifiers.push(notifyValue);
|
|
58
92
|
if (existing.loaded) {
|
|
59
93
|
// Already have the value — notify immediately without re-fetching
|
|
@@ -76,15 +110,21 @@ export class StateOrObjectHandler {
|
|
|
76
110
|
n(obj);
|
|
77
111
|
}
|
|
78
112
|
};
|
|
79
|
-
sub.unsubscribe =
|
|
113
|
+
sub.unsubscribe = notifier => {
|
|
80
114
|
const index = sub.notifiers.indexOf(notifier);
|
|
81
115
|
if (index !== -1) {
|
|
82
116
|
sub.notifiers.splice(index, 1);
|
|
83
117
|
}
|
|
84
|
-
if (sub.notifiers.length === 0) {
|
|
85
|
-
|
|
86
|
-
|
|
118
|
+
if (sub.notifiers.length === 0 && !sub.lingerTimer && !this.destroyed) {
|
|
119
|
+
sub.lingerTimer = setTimeout(() => {
|
|
120
|
+
sub.lingerTimer = undefined;
|
|
121
|
+
if (sub.notifiers.length === 0 && this.objectSubs.get(objectId) === sub) {
|
|
122
|
+
this.objectSubs.delete(objectId);
|
|
123
|
+
void this.socket.unsubscribeObject(objectId, sub.handler);
|
|
124
|
+
}
|
|
125
|
+
}, UNSUBSCRIBE_GRACE_MS);
|
|
87
126
|
}
|
|
127
|
+
return Promise.resolve();
|
|
88
128
|
};
|
|
89
129
|
const obj = await this.socket.getObject(objectId);
|
|
90
130
|
sub.cached = obj;
|
|
@@ -115,6 +155,11 @@ export class StateOrObjectHandler {
|
|
|
115
155
|
};
|
|
116
156
|
const existing = this.stateSubs.get(stateId);
|
|
117
157
|
if (existing) {
|
|
158
|
+
if (existing.lingerTimer) {
|
|
159
|
+
// The subscription was about to be dropped - take it over instead
|
|
160
|
+
clearTimeout(existing.lingerTimer);
|
|
161
|
+
existing.lingerTimer = undefined;
|
|
162
|
+
}
|
|
118
163
|
existing.notifiers.push(notifyValue);
|
|
119
164
|
if (existing.loaded) {
|
|
120
165
|
// Already have the value — notify immediately without re-fetching
|
|
@@ -142,9 +187,14 @@ export class StateOrObjectHandler {
|
|
|
142
187
|
if (index !== -1) {
|
|
143
188
|
sub.notifiers.splice(index, 1);
|
|
144
189
|
}
|
|
145
|
-
if (sub.notifiers.length === 0) {
|
|
146
|
-
|
|
147
|
-
|
|
190
|
+
if (sub.notifiers.length === 0 && !sub.lingerTimer && !this.destroyed) {
|
|
191
|
+
sub.lingerTimer = setTimeout(() => {
|
|
192
|
+
sub.lingerTimer = undefined;
|
|
193
|
+
if (sub.notifiers.length === 0 && this.stateSubs.get(stateId) === sub) {
|
|
194
|
+
this.stateSubs.delete(stateId);
|
|
195
|
+
this.socket.unsubscribeState(stateId, sub.handler);
|
|
196
|
+
}
|
|
197
|
+
}, UNSUBSCRIBE_GRACE_MS);
|
|
148
198
|
}
|
|
149
199
|
};
|
|
150
200
|
const state = await this.socket.getState(stateId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StateOrObjectHandler.js","sourceRoot":"./src/","sources":["StateOrObjectHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Connection, ObjectChangeHandler } from '@iobroker/gui-components';\nimport type { ValueOrStateOrObject } from '@iobroker/dm-utils';\n\ntype ObjectSubscriptionNotifier = (obj?: ioBroker.Object | null) => void;\n\ninterface ObjectSubscription {\n notifiers: ObjectSubscriptionNotifier[];\n handler: ObjectChangeHandler;\n unsubscribe: (notifier: ObjectSubscriptionNotifier) => Promise<void>;\n loaded: boolean;\n cached: ioBroker.Object | null | undefined;\n}\n\ntype StateSubscriptionNotifier = (state?: ioBroker.State | null) => void;\n\ninterface StateSubscription {\n notifiers: StateSubscriptionNotifier[];\n handler: ioBroker.StateChangeHandler;\n unsubscribe: (notifier: StateSubscriptionNotifier) => void;\n loaded: boolean;\n cached: ioBroker.State | null | undefined;\n}\n\nexport interface StateOrObjectSubscription {\n unsubscribe: () => Promise<void> | void;\n}\n\nconst emptySubscription: StateOrObjectSubscription = {\n unsubscribe: () => {},\n};\n\nexport class StateOrObjectHandler {\n private readonly objectSubs = new Map<string, ObjectSubscription>();\n private readonly stateSubs = new Map<string, StateSubscription>();\n\n constructor(private readonly socket: Connection) {}\n\n public async addListener<T extends ioBroker.StringOrTranslated | number | boolean>(\n item: ValueOrStateOrObject<T> | undefined,\n callback: (value: T | undefined) => void,\n ): Promise<StateOrObjectSubscription> {\n if (item === undefined) {\n callback(undefined);\n return emptySubscription;\n }\n\n if (typeof item !== 'object') {\n callback(item);\n return emptySubscription;\n }\n\n if ('en' in item) {\n callback(item as T);\n return emptySubscription;\n }\n\n try {\n if ('objectId' in item) {\n return this.addObjectListener(item.objectId, item.property, callback);\n }\n\n if ('stateId' in item) {\n return this.addStateListener(item.stateId, item.mapping, callback);\n }\n } catch (error) {\n console.error('Error in StateOrObjectHandler:', item, error);\n }\n\n callback(undefined);\n return emptySubscription;\n }\n\n private async addObjectListener<T extends ioBroker.StringOrTranslated | number | boolean>(\n objectId: string,\n property: string,\n callback: (value: T | undefined) => void,\n ): Promise<StateOrObjectSubscription> {\n const notifyValue = (obj?: ioBroker.Object | null): void => {\n if (!obj) {\n callback(undefined);\n return;\n }\n\n const parts = property.split('.');\n let current: any = obj;\n for (const part of parts) {\n if (current[part] === undefined) {\n callback(undefined);\n return;\n }\n current = current[part];\n }\n\n callback(current as T);\n };\n\n const existing = this.objectSubs.get(objectId);\n if (existing) {\n existing.notifiers.push(notifyValue);\n if (existing.loaded) {\n // Already have the value — notify immediately without re-fetching\n notifyValue(existing.cached);\n }\n // If still loading, notifyValue will be called once the load completes\n return { unsubscribe: () => existing.unsubscribe(notifyValue) };\n }\n\n const sub: ObjectSubscription = {\n notifiers: [notifyValue],\n handler: null!,\n unsubscribe: null!,\n loaded: false,\n cached: undefined,\n };\n this.objectSubs.set(objectId, sub);\n\n sub.handler = (_id, obj) => {\n sub.cached = obj;\n for (const n of sub.notifiers) {\n n(obj);\n }\n };\n sub.unsubscribe = async notifier => {\n const index = sub.notifiers.indexOf(notifier);\n if (index !== -1) {\n sub.notifiers.splice(index, 1);\n }\n if (sub.notifiers.length === 0) {\n this.objectSubs.delete(objectId);\n await this.socket.unsubscribeObject(objectId, sub.handler);\n }\n };\n\n const obj = await this.socket.getObject(objectId);\n sub.cached = obj;\n sub.loaded = true;\n // Notify all notifiers (including any added while getObject was in progress)\n for (const n of sub.notifiers) {\n n(obj);\n }\n await this.socket.subscribeObject(objectId, sub.handler);\n return { unsubscribe: () => sub.unsubscribe(notifyValue) };\n }\n\n private async addStateListener<T extends ioBroker.StringOrTranslated | number | boolean>(\n stateId: string,\n mapping: Record<string | number, T> | undefined,\n callback: (value: T | undefined) => void,\n ): Promise<StateOrObjectSubscription> {\n const notifyValue = (state?: ioBroker.State | null): void => {\n let val = state?.val;\n if (val === undefined || val === null) {\n callback(undefined);\n return;\n }\n\n if (mapping) {\n if (typeof val === 'boolean') {\n val = val.toString();\n }\n\n callback(mapping[val]);\n } else {\n callback(val as T);\n }\n };\n\n const existing = this.stateSubs.get(stateId);\n if (existing) {\n existing.notifiers.push(notifyValue);\n if (existing.loaded) {\n // Already have the value — notify immediately without re-fetching\n notifyValue(existing.cached);\n }\n // If still loading, notifyValue will be called once the load completes\n return { unsubscribe: () => existing.unsubscribe(notifyValue) };\n }\n\n const sub: StateSubscription = {\n notifiers: [notifyValue],\n handler: null!,\n unsubscribe: null!,\n loaded: false,\n cached: undefined,\n };\n this.stateSubs.set(stateId, sub);\n\n sub.handler = (_id, state) => {\n sub.cached = state;\n for (const n of sub.notifiers) {\n n(state);\n }\n };\n sub.unsubscribe = notifier => {\n const index = sub.notifiers.indexOf(notifier);\n if (index !== -1) {\n sub.notifiers.splice(index, 1);\n }\n if (sub.notifiers.length === 0) {\n this.stateSubs.delete(stateId);\n this.socket.unsubscribeState(stateId, sub.handler);\n }\n };\n\n const state = await this.socket.getState(stateId);\n sub.cached = state;\n sub.loaded = true;\n // Notify all notifiers (including any added while the fetch was in progress)\n for (const n of sub.notifiers) {\n n(state);\n }\n await this.socket.subscribeState(stateId, sub.handler);\n return { unsubscribe: () => sub.unsubscribe(notifyValue) };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"StateOrObjectHandler.js","sourceRoot":"./src/","sources":["StateOrObjectHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Connection, ObjectChangeHandler } from '@iobroker/gui-components';\nimport type { ValueOrStateOrObject } from '@iobroker/dm-utils';\n\ntype ObjectSubscriptionNotifier = (obj?: ioBroker.Object | null) => void;\n\ninterface ObjectSubscription {\n notifiers: ObjectSubscriptionNotifier[];\n handler: ObjectChangeHandler;\n unsubscribe: (notifier: ObjectSubscriptionNotifier) => Promise<void>;\n loaded: boolean;\n cached: ioBroker.Object | null | undefined;\n /** Set while the subscription is waiting for the grace period after its last notifier left */\n lingerTimer?: ReturnType<typeof setTimeout>;\n}\n\ntype StateSubscriptionNotifier = (state?: ioBroker.State | null) => void;\n\ninterface StateSubscription {\n notifiers: StateSubscriptionNotifier[];\n handler: ioBroker.StateChangeHandler;\n unsubscribe: (notifier: StateSubscriptionNotifier) => void;\n loaded: boolean;\n cached: ioBroker.State | null | undefined;\n /** Set while the subscription is waiting for the grace period after its last notifier left */\n lingerTimer?: ReturnType<typeof setTimeout>;\n}\n\nexport interface StateOrObjectSubscription {\n unsubscribe: () => Promise<void> | void;\n}\n\nconst emptySubscription: StateOrObjectSubscription = {\n unsubscribe: () => {},\n};\n\n/**\n * How long a subscription without any listener is kept before it is really unsubscribed.\n *\n * The cards of the device list are mounted and unmounted while scrolling. Without this grace period\n * every card that scrolls in and out again would cause a new `getObject`/`getState` round trip plus\n * a new subscription on the socket.\n */\nconst UNSUBSCRIBE_GRACE_MS = 10_000;\n\nexport class StateOrObjectHandler {\n private readonly objectSubs = new Map<string, ObjectSubscription>();\n private readonly stateSubs = new Map<string, StateSubscription>();\n\n private destroyed = false;\n\n constructor(private readonly socket: Connection) {}\n\n /** Unsubscribe everything. To be called when the component owning this handler is unmounted */\n public destroy(): void {\n this.destroyed = true;\n for (const [objectId, sub] of this.objectSubs) {\n if (sub.lingerTimer) {\n clearTimeout(sub.lingerTimer);\n }\n sub.notifiers.length = 0;\n void this.socket.unsubscribeObject(objectId, sub.handler);\n }\n this.objectSubs.clear();\n\n for (const [stateId, sub] of this.stateSubs) {\n if (sub.lingerTimer) {\n clearTimeout(sub.lingerTimer);\n }\n sub.notifiers.length = 0;\n this.socket.unsubscribeState(stateId, sub.handler);\n }\n this.stateSubs.clear();\n }\n\n public async addListener<T extends ioBroker.StringOrTranslated | number | boolean>(\n item: ValueOrStateOrObject<T> | undefined,\n callback: (value: T | undefined) => void,\n ): Promise<StateOrObjectSubscription> {\n if (item === undefined) {\n callback(undefined);\n return emptySubscription;\n }\n\n if (typeof item !== 'object') {\n callback(item);\n return emptySubscription;\n }\n\n if ('en' in item) {\n callback(item as T);\n return emptySubscription;\n }\n\n try {\n if ('objectId' in item) {\n return this.addObjectListener(item.objectId, item.property, callback);\n }\n\n if ('stateId' in item) {\n return this.addStateListener(item.stateId, item.mapping, callback);\n }\n } catch (error) {\n console.error('Error in StateOrObjectHandler:', item, error);\n }\n\n callback(undefined);\n return emptySubscription;\n }\n\n private async addObjectListener<T extends ioBroker.StringOrTranslated | number | boolean>(\n objectId: string,\n property: string,\n callback: (value: T | undefined) => void,\n ): Promise<StateOrObjectSubscription> {\n const notifyValue = (obj?: ioBroker.Object | null): void => {\n if (!obj) {\n callback(undefined);\n return;\n }\n\n const parts = property.split('.');\n let current: any = obj;\n for (const part of parts) {\n if (current[part] === undefined) {\n callback(undefined);\n return;\n }\n current = current[part];\n }\n\n callback(current as T);\n };\n\n const existing = this.objectSubs.get(objectId);\n if (existing) {\n if (existing.lingerTimer) {\n // The subscription was about to be dropped - take it over instead\n clearTimeout(existing.lingerTimer);\n existing.lingerTimer = undefined;\n }\n existing.notifiers.push(notifyValue);\n if (existing.loaded) {\n // Already have the value — notify immediately without re-fetching\n notifyValue(existing.cached);\n }\n // If still loading, notifyValue will be called once the load completes\n return { unsubscribe: () => existing.unsubscribe(notifyValue) };\n }\n\n const sub: ObjectSubscription = {\n notifiers: [notifyValue],\n handler: null!,\n unsubscribe: null!,\n loaded: false,\n cached: undefined,\n };\n this.objectSubs.set(objectId, sub);\n\n sub.handler = (_id, obj) => {\n sub.cached = obj;\n for (const n of sub.notifiers) {\n n(obj);\n }\n };\n sub.unsubscribe = notifier => {\n const index = sub.notifiers.indexOf(notifier);\n if (index !== -1) {\n sub.notifiers.splice(index, 1);\n }\n if (sub.notifiers.length === 0 && !sub.lingerTimer && !this.destroyed) {\n sub.lingerTimer = setTimeout(() => {\n sub.lingerTimer = undefined;\n if (sub.notifiers.length === 0 && this.objectSubs.get(objectId) === sub) {\n this.objectSubs.delete(objectId);\n void this.socket.unsubscribeObject(objectId, sub.handler);\n }\n }, UNSUBSCRIBE_GRACE_MS);\n }\n return Promise.resolve();\n };\n\n const obj = await this.socket.getObject(objectId);\n sub.cached = obj;\n sub.loaded = true;\n // Notify all notifiers (including any added while getObject was in progress)\n for (const n of sub.notifiers) {\n n(obj);\n }\n await this.socket.subscribeObject(objectId, sub.handler);\n return { unsubscribe: () => sub.unsubscribe(notifyValue) };\n }\n\n private async addStateListener<T extends ioBroker.StringOrTranslated | number | boolean>(\n stateId: string,\n mapping: Record<string | number, T> | undefined,\n callback: (value: T | undefined) => void,\n ): Promise<StateOrObjectSubscription> {\n const notifyValue = (state?: ioBroker.State | null): void => {\n let val = state?.val;\n if (val === undefined || val === null) {\n callback(undefined);\n return;\n }\n\n if (mapping) {\n if (typeof val === 'boolean') {\n val = val.toString();\n }\n\n callback(mapping[val]);\n } else {\n callback(val as T);\n }\n };\n\n const existing = this.stateSubs.get(stateId);\n if (existing) {\n if (existing.lingerTimer) {\n // The subscription was about to be dropped - take it over instead\n clearTimeout(existing.lingerTimer);\n existing.lingerTimer = undefined;\n }\n existing.notifiers.push(notifyValue);\n if (existing.loaded) {\n // Already have the value — notify immediately without re-fetching\n notifyValue(existing.cached);\n }\n // If still loading, notifyValue will be called once the load completes\n return { unsubscribe: () => existing.unsubscribe(notifyValue) };\n }\n\n const sub: StateSubscription = {\n notifiers: [notifyValue],\n handler: null!,\n unsubscribe: null!,\n loaded: false,\n cached: undefined,\n };\n this.stateSubs.set(stateId, sub);\n\n sub.handler = (_id, state) => {\n sub.cached = state;\n for (const n of sub.notifiers) {\n n(state);\n }\n };\n sub.unsubscribe = notifier => {\n const index = sub.notifiers.indexOf(notifier);\n if (index !== -1) {\n sub.notifiers.splice(index, 1);\n }\n if (sub.notifiers.length === 0 && !sub.lingerTimer && !this.destroyed) {\n sub.lingerTimer = setTimeout(() => {\n sub.lingerTimer = undefined;\n if (sub.notifiers.length === 0 && this.stateSubs.get(stateId) === sub) {\n this.stateSubs.delete(stateId);\n this.socket.unsubscribeState(stateId, sub.handler);\n }\n }, UNSUBSCRIBE_GRACE_MS);\n }\n };\n\n const state = await this.socket.getState(stateId);\n sub.cached = state;\n sub.loaded = true;\n // Notify all notifiers (including any added while the fetch was in progress)\n for (const n of sub.notifiers) {\n n(state);\n }\n await this.socket.subscribeState(stateId, sub.handler);\n return { unsubscribe: () => sub.unsubscribe(notifyValue) };\n }\n}\n"]}
|
package/build/TooltipButton.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ interface TooltipButtonProps {
|
|
|
7
7
|
onClick?: () => void;
|
|
8
8
|
url?: string;
|
|
9
9
|
variant?: 'text' | 'outlined' | 'contained';
|
|
10
|
+
/** `inherit` takes the text color of the parent, e.g. on a colored toolbar. Default is the primary color */
|
|
11
|
+
color?: 'inherit' | 'primary';
|
|
10
12
|
style?: Record<string, any>;
|
|
11
13
|
}
|
|
12
14
|
export default function TooltipButton(props: TooltipButtonProps): React.JSX.Element;
|
package/build/TooltipButton.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Button, IconButton, Tooltip, Typography } from '@mui/material';
|
|
3
3
|
export default function TooltipButton(props) {
|
|
4
|
-
const { tooltip, label, disabled, Icon, onClick, url } = props;
|
|
4
|
+
const { tooltip, label, disabled, Icon, onClick, url, color } = props;
|
|
5
5
|
const text = label ? (React.createElement(Typography, { variant: "button", sx: props.style,
|
|
6
6
|
// The gap is only required if an icon is shown in front of the text
|
|
7
7
|
style: { marginLeft: Icon ? 4 : undefined } }, label)) : null;
|
|
8
|
-
const btnProps = url ? { href: url, disabled, target: '_blank' } : { onClick, disabled };
|
|
8
|
+
const btnProps = url ? { href: url, disabled, target: '_blank', color } : { onClick, disabled, color };
|
|
9
9
|
if (tooltip) {
|
|
10
10
|
return (React.createElement(Tooltip, { title: tooltip, slotProps: { popper: { sx: { pointerEvents: 'none' } } } },
|
|
11
11
|
React.createElement("span", null, text ? (React.createElement(Button, { ...btnProps, sx: props.style, variant: props.variant, startIcon: Icon }, text)) : (React.createElement(IconButton, { ...btnProps, sx: props.style, size: "small" }, Icon)))));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TooltipButton.js","sourceRoot":"./src/","sources":["TooltipButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"TooltipButton.js","sourceRoot":"./src/","sources":["TooltipButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAexE,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,KAAyB;IAC3D,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IAEtE,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CACjB,oBAAC,UAAU,IACP,OAAO,EAAC,QAAQ,EAChB,EAAE,EAAE,KAAK,CAAC,KAAK;QACf,oEAAoE;QACpE,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,IAE1C,KAAK,CACG,CAChB,CAAC,CAAC,CAAC,IAAI,CAAC;IAET,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAEvG,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,CACH,oBAAC,OAAO,IACJ,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,EAAE;YAExD,kCACK,IAAI,CAAC,CAAC,CAAC,CACJ,oBAAC,MAAM,OACC,QAAQ,EACZ,EAAE,EAAE,KAAK,CAAC,KAAK,EACf,OAAO,EAAE,KAAK,CAAC,OAAO,EACtB,SAAS,EAAE,IAAI,IAEd,IAAI,CACA,CACZ,CAAC,CAAC,CAAC,CACA,oBAAC,UAAU,OACH,QAAQ,EACZ,EAAE,EAAE,KAAK,CAAC,KAAK,EACf,IAAI,EAAC,OAAO,IAEX,IAAI,CACI,CAChB,CACE,CACD,CACb,CAAC;IACN,CAAC;IAED,OAAO,IAAI,CAAC,CAAC,CAAC,CACV,oBAAC,MAAM,OACC,QAAQ,EACZ,EAAE,EAAE,KAAK,CAAC,KAAK,EACf,OAAO,EAAE,KAAK,CAAC,OAAO,EACtB,SAAS,EAAE,IAAI,IAEd,IAAI,CACA,CACZ,CAAC,CAAC,CAAC,CACA,oBAAC,UAAU,OACH,QAAQ,EACZ,EAAE,EAAE,KAAK,CAAC,KAAK,EACf,IAAI,EAAC,OAAO,IAEX,IAAI,CACI,CAChB,CAAC;AACN,CAAC","sourcesContent":["import React from 'react';\nimport { Button, IconButton, Tooltip, Typography } from '@mui/material';\n\ninterface TooltipButtonProps {\n tooltip?: string;\n label?: string;\n disabled?: boolean;\n Icon: React.JSX.Element | null;\n onClick?: () => void;\n url?: string;\n variant?: 'text' | 'outlined' | 'contained';\n /** `inherit` takes the text color of the parent, e.g. on a colored toolbar. Default is the primary color */\n color?: 'inherit' | 'primary';\n style?: Record<string, any>;\n}\n\nexport default function TooltipButton(props: TooltipButtonProps): React.JSX.Element {\n const { tooltip, label, disabled, Icon, onClick, url, color } = props;\n\n const text = label ? (\n <Typography\n variant=\"button\"\n sx={props.style}\n // The gap is only required if an icon is shown in front of the text\n style={{ marginLeft: Icon ? 4 : undefined }}\n >\n {label}\n </Typography>\n ) : null;\n\n const btnProps = url ? { href: url, disabled, target: '_blank', color } : { onClick, disabled, color };\n\n if (tooltip) {\n return (\n <Tooltip\n title={tooltip}\n slotProps={{ popper: { sx: { pointerEvents: 'none' } } }}\n >\n <span>\n {text ? (\n <Button\n {...btnProps}\n sx={props.style}\n variant={props.variant}\n startIcon={Icon}\n >\n {text}\n </Button>\n ) : (\n <IconButton\n {...btnProps}\n sx={props.style}\n size=\"small\"\n >\n {Icon}\n </IconButton>\n )}\n </span>\n </Tooltip>\n );\n }\n\n return text ? (\n <Button\n {...btnProps}\n sx={props.style}\n variant={props.variant}\n startIcon={Icon}\n >\n {text}\n </Button>\n ) : (\n <IconButton\n {...btnProps}\n sx={props.style}\n size=\"small\"\n >\n {Icon}\n </IconButton>\n );\n}\n"]}
|
package/build/Utils.d.ts
CHANGED
|
@@ -30,3 +30,10 @@ export declare function renderActionIcon(action: ActionBase, noDefaultIcon?: boo
|
|
|
30
30
|
export declare function getTranslation(
|
|
31
31
|
/** Text to translate */
|
|
32
32
|
text: ioBroker.StringOrTranslated, noTranslation?: boolean): string;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a possibly translated text into the current language.
|
|
35
|
+
*
|
|
36
|
+
* Unlike `getTranslation`, a plain string is returned untouched: device names, models and
|
|
37
|
+
* manufacturers are data, not keys of the i18n dictionary.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getText(text: ioBroker.StringOrTranslated | undefined): string | undefined;
|
package/build/Utils.js
CHANGED
|
@@ -322,4 +322,17 @@ text, noTranslation) {
|
|
|
322
322
|
}
|
|
323
323
|
return noTranslation ? text : I18n.t(text);
|
|
324
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Resolve a possibly translated text into the current language.
|
|
327
|
+
*
|
|
328
|
+
* Unlike `getTranslation`, a plain string is returned untouched: device names, models and
|
|
329
|
+
* manufacturers are data, not keys of the i18n dictionary.
|
|
330
|
+
*/
|
|
331
|
+
export function getText(text) {
|
|
332
|
+
if (typeof text === 'object') {
|
|
333
|
+
language ||= I18n.getLanguage();
|
|
334
|
+
return text[language] || text.en;
|
|
335
|
+
}
|
|
336
|
+
return text;
|
|
337
|
+
}
|
|
325
338
|
//# sourceMappingURL=Utils.js.map
|
package/build/Utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Utils.js","sourceRoot":"./src/","sources":["Utils.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\n\nimport type { ActionBase, ControlBase, IndicatorColor } from './protocol/api';\nimport {\n Add,\n Article,\n BatteryAlert,\n BatteryChargingFull,\n BatteryFull,\n Bluetooth,\n BluetoothDisabled,\n Delete,\n Edit,\n FastForward,\n FastRewind,\n Fluorescent,\n Group,\n Info,\n Lightbulb,\n Link as LinkIcon,\n LinkOff,\n NotListedLocation,\n Pause,\n Person,\n PlayArrow,\n Power,\n QrCode,\n QuestionMark,\n Refresh,\n Search,\n Settings,\n Stop,\n Visibility,\n Upgrade,\n WbIncandescent,\n Wifi,\n WifiOff,\n Launch,\n} from '@mui/icons-material';\n\nimport { I18n, Icon, type IobTheme } from '@iobroker/gui-components';\n\n/**\n * Get Icon by font-awesome name. Do not use these names, use names from getIconByName\n *\n * @param icon font-awesome icon name\n * Only following font-awesome icons are supported:\n * - fa-trash-can, fa-trash\n * - fa-pen\n * - fa-redo-alt\n * - fa-plus\n * - fa-qrcode, qrcode\n * - fa-wifi\n * - fa-wifi-slash\n * - fa-bluetooth\n * - fa-bluetooth-slash\n * - fa-eye\n * - fa-search\n * - fa-unlink\n * - fa-link\n * - fa-search-location\n * - fa-play\n * - fa-stop\n * - fa-pause\n * @param color color of the icon\n */\nfunction getFaIcon(icon: string, color?: string): React.JSX.Element | null {\n const iconStyle = icon\n .split(' ')\n .map(s => s.trim())\n .filter(s => s !== 'fa-solid');\n\n if (iconStyle.includes('fa-trash-can') || iconStyle.includes('fa-trash')) {\n return <Delete style={{ color }} />;\n }\n if (iconStyle.includes('fa-pen')) {\n return <Edit style={{ color }} />;\n }\n if (iconStyle.includes('fa-redo-alt')) {\n return <Refresh style={{ color }} />;\n }\n if (iconStyle.includes('fa-plus')) {\n return <Add style={{ color }} />;\n }\n if (iconStyle.includes('fa-qrcode') || iconStyle.includes('qrcode')) {\n return <QrCode style={{ color }} />;\n }\n if (iconStyle.includes('fa-wifi')) {\n return <Wifi style={{ color }} />;\n }\n if (iconStyle.includes('fa-wifi-slash')) {\n return <WifiOff style={{ color }} />;\n }\n if (iconStyle.includes('fa-bluetooth')) {\n return <Bluetooth style={{ color }} />;\n }\n if (iconStyle.includes('fa-bluetooth-slash')) {\n return <BluetoothDisabled style={{ color }} />;\n }\n if (iconStyle.includes('fa-eye')) {\n return <Visibility style={{ color }} />;\n }\n if (iconStyle.includes('fa-search')) {\n return <Search style={{ color }} />;\n }\n if (iconStyle.includes('fa-unlink')) {\n return <LinkOff style={{ color }} />;\n }\n if (iconStyle.includes('fa-link')) {\n return <LinkIcon style={{ color }} />;\n }\n if (iconStyle.includes('fa-search-location')) {\n return <NotListedLocation style={{ color }} />;\n }\n if (iconStyle.includes('fa-play')) {\n return <PlayArrow style={{ color }} />;\n }\n if (iconStyle.includes('fa-stop')) {\n return <Stop style={{ color }} />;\n }\n if (iconStyle.includes('fa-pause')) {\n return <Pause style={{ color }} />;\n }\n return <QuestionMark style={{ color }} />;\n}\n\n/**\n * Get Icon by name or by action\n *\n * @param name action name\n * possible action or icon names are\n * - edit, rename\n * - delete\n * - refresh\n * - newDevice, new, add\n * - discover, search\n * - unpairDevice, unpair\n * - pairDevice, pair\n * - identify\n * - play\n * - stop\n * - pause\n * - forward, next\n * - rewind, previous\n * - lamp, light\n * - backlight\n * - dimmer\n * - socket\n * - settings\n * - users, group\n * - user\n * - qrcode\n * - identify\n * - info\n * - lines\n * - battery\n * - batteryLow, batteryAlert\n * - batteryCharging\n * @param altName icon name\n * @param color color of the icon\n * @param noDefaultIcon if true, no \"question mark\" icon will be returned for unknown names\n */\nfunction getIconByName(\n name: string,\n altName?: string,\n color?: string,\n noDefaultIcon?: boolean,\n): React.JSX.Element | null {\n if (name === 'edit' || name === 'rename' || altName === 'edit' || altName === 'rename') {\n return <Edit style={{ color }} />;\n }\n if (name === 'delete' || altName === 'delete') {\n return <Delete style={{ color }} />;\n }\n if (name === 'refresh' || altName === 'refresh') {\n return <Refresh style={{ color }} />;\n }\n if (\n name === 'newDevice' ||\n name === 'new' ||\n name === 'add' ||\n altName === 'newDevice' ||\n altName === 'new' ||\n altName === 'add'\n ) {\n return <Add style={{ color }} />;\n }\n if (name === 'discover' || name === 'search' || altName === 'discover' || altName === 'search') {\n return <Search style={{ color }} />;\n }\n if (name === 'unpairDevice' || name === 'unpair' || altName === 'unpairDevice' || altName === 'unpair') {\n return <LinkOff style={{ color }} />;\n }\n if (name === 'pairDevice' || name === 'pair' || altName === 'pairDevice' || altName === 'pair') {\n return <LinkIcon style={{ color }} />;\n }\n if (name === 'identify' || altName === 'identify') {\n return <NotListedLocation style={{ color }} />;\n }\n if (name === 'play' || altName === 'play') {\n return <PlayArrow style={{ color }} />;\n }\n if (name === 'stop' || altName === 'stop') {\n return <Stop style={{ color }} />;\n }\n if (name === 'pause' || altName === 'pause') {\n return <Pause style={{ color }} />;\n }\n if (name === 'forward' || name === 'next' || altName === 'forward' || altName === 'next') {\n return <FastForward style={{ color }} />;\n }\n if (name === 'rewind' || name === 'previous' || altName === 'rewind' || altName === 'previous') {\n return <FastRewind style={{ color }} />;\n }\n if (name === 'lamp' || name === 'light' || altName === 'lamp' || altName === 'light') {\n return <Lightbulb style={{ color }} />;\n }\n if (name === 'backlight' || altName === 'backlight') {\n return <Fluorescent style={{ color }} />;\n }\n if (name === 'dimmer' || altName === 'dimmer') {\n return <WbIncandescent style={{ color }} />;\n }\n if (name === 'socket' || altName === 'socket') {\n return <Power style={{ color }} />;\n }\n if (name === 'settings' || altName === 'settings') {\n return <Settings style={{ color }} />;\n }\n if (name === 'users' || name === 'group' || altName === 'users' || altName === 'group') {\n return <Group style={{ color }} />;\n }\n if (name === 'user' || altName === 'user') {\n return <Person style={{ color }} />;\n }\n if (name === 'update' || altName === 'update') {\n return <Upgrade style={{ color }} />;\n }\n if (name === 'qrcode' || altName === 'qrcode') {\n return <QrCode style={{ color }} />;\n }\n if (name === 'info' || altName === 'info') {\n return <Info style={{ color }} />;\n }\n if (name === 'lines' || altName === 'lines') {\n return <Article style={{ color }} />;\n }\n if (name === 'web' || altName === 'web') {\n return <Launch style={{ color }} />;\n }\n if (name === 'battery' || altName === 'battery') {\n return <BatteryFull style={{ color }} />;\n }\n if (name === 'batteryLow' || name === 'batteryAlert' || altName === 'batteryLow' || altName === 'batteryAlert') {\n return <BatteryAlert style={{ color }} />;\n }\n if (name === 'batteryCharging' || altName === 'batteryCharging') {\n return <BatteryChargingFull style={{ color }} />;\n }\n if (noDefaultIcon) {\n return null;\n }\n return <QuestionMark style={{ color }} />;\n}\n\nexport function renderControlIcon(\n action: ControlBase,\n colors?: { primary: string; secondary: string },\n value?: string | number | boolean | null,\n noDefaultIcon?: boolean,\n): React.JSX.Element | null {\n if (!action) {\n return null;\n }\n\n let color = (value && action.colorOn) || action.color || (action.state ? 'primary' : 'inherit');\n\n if (colors) {\n if (color === 'primary') {\n color = colors.primary;\n } else if (color === 'secondary') {\n color = colors.secondary;\n }\n }\n\n if (action.icon?.startsWith('fa-') || action.icon?.startsWith('fas')) {\n return getFaIcon(action.icon, color);\n }\n if (value && action.iconOn?.startsWith('data:image')) {\n return (\n <Icon\n src={action.iconOn}\n style={{ color }}\n />\n );\n }\n if (action.icon?.startsWith('data:image')) {\n return (\n <Icon\n src={action.icon}\n style={{ color }}\n />\n );\n }\n if (!noDefaultIcon) {\n return getIconByName(action.id, action.icon, color);\n }\n return null;\n}\n\n/**\n * Render an icon that is given as a plain name (and not as a part of an action or control)\n *\n * @param icon `fa-*` name, `data:image/...` string, URL or one of the names supported by `getIconByName`\n * @param color color of the icon\n * @param noDefaultIcon if true, no \"question mark\" icon will be returned for unknown or missing names\n */\nexport function renderIcon(icon?: string, color?: string, noDefaultIcon?: boolean): React.JSX.Element | null {\n if (!icon) {\n return noDefaultIcon ? null : <QuestionMark style={{ color }} />;\n }\n if (icon.startsWith('fa-') || icon.startsWith('fas')) {\n return getFaIcon(icon, color);\n }\n if (\n icon.startsWith('data:image') ||\n icon.startsWith('http://') ||\n icon.startsWith('https://') ||\n icon.includes('/') ||\n /\\.(png|jpe?g|svg|gif|webp|ico)$/i.test(icon)\n ) {\n return (\n <Icon\n src={icon}\n style={{ color }}\n />\n );\n }\n return getIconByName(icon, undefined, color, noDefaultIcon);\n}\n\n/**\n * Resolve the color of a status indicator.\n *\n * The semantic tokens use the same colors as the built-in status icons, but adapted to the theme,\n * so custom indicators do not look foreign next to connection, battery, warning and update.\n *\n * @param color semantic token, `primary`, `secondary` or an explicit CSS color\n * @param theme current theme\n */\nexport function getIndicatorColor(color: IndicatorColor | undefined, theme: IobTheme): string | undefined {\n if (!color) {\n return undefined;\n }\n const dark = theme.palette.mode === 'dark';\n\n switch (color) {\n case 'ok':\n return dark ? '#5cff5c' : '#00ac00';\n case 'warning':\n return dark ? '#ffa733' : '#da8200';\n case 'error':\n return dark ? '#ff5c5c' : '#ff0000';\n case 'info':\n return dark ? '#64b5f6' : '#2196f3';\n case 'inactive':\n return '#8a8a8a';\n case 'primary':\n return theme.palette.primary.main;\n case 'secondary':\n return theme.palette.secondary.main;\n default:\n return color;\n }\n}\n\nexport function renderActionIcon(action: ActionBase, noDefaultIcon?: boolean): React.JSX.Element | null {\n if (!action) {\n return null;\n }\n\n if (action.icon?.startsWith('fa-') || action.icon?.startsWith('fas')) {\n return getFaIcon(action.icon, action.color);\n }\n if (action.icon?.startsWith('data:image')) {\n return (\n <Icon\n src={action.icon}\n style={{ color: action.color }}\n />\n );\n }\n return getIconByName(action.id, action.icon, action.color, noDefaultIcon);\n}\n\nlet language: ioBroker.Languages;\n\n/**\n * Get Translation\n */\nexport function getTranslation(\n /** Text to translate */\n text: ioBroker.StringOrTranslated,\n noTranslation?: boolean,\n): string {\n language ||= I18n.getLanguage();\n\n if (typeof text === 'object') {\n return text[language] || text.en;\n }\n\n return noTranslation ? text : I18n.t(text);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Utils.js","sourceRoot":"./src/","sources":["Utils.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EACH,GAAG,EACH,OAAO,EACP,YAAY,EACZ,mBAAmB,EACnB,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,MAAM,EACN,IAAI,EACJ,WAAW,EACX,UAAU,EACV,WAAW,EACX,KAAK,EACL,IAAI,EACJ,SAAS,EACT,IAAI,IAAI,QAAQ,EAChB,OAAO,EACP,iBAAiB,EACjB,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,MAAM,EACN,YAAY,EACZ,OAAO,EACP,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,UAAU,EACV,OAAO,EACP,cAAc,EACd,IAAI,EACJ,OAAO,EACP,MAAM,GACT,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAiB,MAAM,0BAA0B,CAAC;AAErE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAS,SAAS,CAAC,IAAY,EAAE,KAAc;IAC3C,MAAM,SAAS,GAAG,IAAI;SACjB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SAClB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC;IAEnC,IAAI,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACvE,OAAO,oBAAC,MAAM,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACxC,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,OAAO,oBAAC,IAAI,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACtC,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QACpC,OAAO,oBAAC,OAAO,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACzC,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,OAAO,oBAAC,GAAG,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACrC,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClE,OAAO,oBAAC,MAAM,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACxC,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,OAAO,oBAAC,IAAI,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACtC,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;QACtC,OAAO,oBAAC,OAAO,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACzC,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACrC,OAAO,oBAAC,SAAS,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC3C,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAC3C,OAAO,oBAAC,iBAAiB,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACnD,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,OAAO,oBAAC,UAAU,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC5C,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAClC,OAAO,oBAAC,MAAM,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACxC,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAClC,OAAO,oBAAC,OAAO,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACzC,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,OAAO,oBAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC1C,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAC3C,OAAO,oBAAC,iBAAiB,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACnD,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,OAAO,oBAAC,SAAS,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC3C,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,OAAO,oBAAC,IAAI,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACtC,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACjC,OAAO,oBAAC,KAAK,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACvC,CAAC;IACD,OAAO,oBAAC,YAAY,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,SAAS,aAAa,CAClB,IAAY,EACZ,OAAgB,EAChB,KAAc,EACd,aAAuB;IAEvB,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACrF,OAAO,oBAAC,IAAI,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACtC,CAAC;IACD,IAAI,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,oBAAC,MAAM,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACxC,CAAC;IACD,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC9C,OAAO,oBAAC,OAAO,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACzC,CAAC;IACD,IACI,IAAI,KAAK,WAAW;QACpB,IAAI,KAAK,KAAK;QACd,IAAI,KAAK,KAAK;QACd,OAAO,KAAK,WAAW;QACvB,OAAO,KAAK,KAAK;QACjB,OAAO,KAAK,KAAK,EACnB,CAAC;QACC,OAAO,oBAAC,GAAG,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACrC,CAAC;IACD,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC7F,OAAO,oBAAC,MAAM,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACxC,CAAC;IACD,IAAI,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,cAAc,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACrG,OAAO,oBAAC,OAAO,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACzC,CAAC;IACD,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,YAAY,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QAC7F,OAAO,oBAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC1C,CAAC;IACD,IAAI,IAAI,KAAK,UAAU,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAChD,OAAO,oBAAC,iBAAiB,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACnD,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACxC,OAAO,oBAAC,SAAS,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC3C,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACxC,OAAO,oBAAC,IAAI,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACtC,CAAC;IACD,IAAI,IAAI,KAAK,OAAO,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QAC1C,OAAO,oBAAC,KAAK,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACvC,CAAC;IACD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvF,OAAO,oBAAC,WAAW,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC7C,CAAC;IACD,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,UAAU,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAC7F,OAAO,oBAAC,UAAU,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC5C,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,OAAO,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACnF,OAAO,oBAAC,SAAS,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC3C,CAAC;IACD,IAAI,IAAI,KAAK,WAAW,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QAClD,OAAO,oBAAC,WAAW,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC7C,CAAC;IACD,IAAI,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,oBAAC,cAAc,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAChD,CAAC;IACD,IAAI,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,oBAAC,KAAK,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACvC,CAAC;IACD,IAAI,IAAI,KAAK,UAAU,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAChD,OAAO,oBAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC1C,CAAC;IACD,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACrF,OAAO,oBAAC,KAAK,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACvC,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACxC,OAAO,oBAAC,MAAM,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACxC,CAAC;IACD,IAAI,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,oBAAC,OAAO,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACzC,CAAC;IACD,IAAI,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,oBAAC,MAAM,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACxC,CAAC;IACD,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACxC,OAAO,oBAAC,IAAI,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACtC,CAAC;IACD,IAAI,IAAI,KAAK,OAAO,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QAC1C,OAAO,oBAAC,OAAO,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACzC,CAAC;IACD,IAAI,IAAI,KAAK,KAAK,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtC,OAAO,oBAAC,MAAM,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACxC,CAAC;IACD,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC9C,OAAO,oBAAC,WAAW,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC7C,CAAC;IACD,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,cAAc,IAAI,OAAO,KAAK,YAAY,IAAI,OAAO,KAAK,cAAc,EAAE,CAAC;QAC7G,OAAO,oBAAC,YAAY,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IAC9C,CAAC;IACD,IAAI,IAAI,KAAK,iBAAiB,IAAI,OAAO,KAAK,iBAAiB,EAAE,CAAC;QAC9D,OAAO,oBAAC,mBAAmB,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACrD,CAAC;IACD,IAAI,aAAa,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,oBAAC,YAAY,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC7B,MAAmB,EACnB,MAA+C,EAC/C,KAAwC,EACxC,aAAuB;IAEvB,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,KAAK,GAAG,CAAC,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAEhG,IAAI,MAAM,EAAE,CAAC;QACT,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACtB,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC;QAC3B,CAAC;aAAM,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;YAC/B,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC;QAC7B,CAAC;IACL,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACnE,OAAO,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACnD,OAAO,CACH,oBAAC,IAAI,IACD,GAAG,EAAE,MAAM,CAAC,MAAM,EAClB,KAAK,EAAE,EAAE,KAAK,EAAE,GAClB,CACL,CAAC;IACN,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACxC,OAAO,CACH,oBAAC,IAAI,IACD,GAAG,EAAE,MAAM,CAAC,IAAI,EAChB,KAAK,EAAE,EAAE,KAAK,EAAE,GAClB,CACL,CAAC;IACN,CAAC;IACD,IAAI,CAAC,aAAa,EAAE,CAAC;QACjB,OAAO,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,IAAa,EAAE,KAAc,EAAE,aAAuB;IAC7E,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,oBAAC,YAAY,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAI,CAAC;IACrE,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACnD,OAAO,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IACD,IACI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAC1B,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAClB,kCAAkC,CAAC,IAAI,CAAC,IAAI,CAAC,EAC/C,CAAC;QACC,OAAO,CACH,oBAAC,IAAI,IACD,GAAG,EAAE,IAAI,EACT,KAAK,EAAE,EAAE,KAAK,EAAE,GAClB,CACL,CAAC;IACN,CAAC;IACD,OAAO,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAiC,EAAE,KAAe;IAChF,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC;IAE3C,QAAQ,KAAK,EAAE,CAAC;QACZ,KAAK,IAAI;YACL,OAAO,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QACxC,KAAK,SAAS;YACV,OAAO,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QACxC,KAAK,OAAO;YACR,OAAO,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QACxC,KAAK,MAAM;YACP,OAAO,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QACxC,KAAK,UAAU;YACX,OAAO,SAAS,CAAC;QACrB,KAAK,SAAS;YACV,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;QACtC,KAAK,WAAW;YACZ,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC;QACxC;YACI,OAAO,KAAK,CAAC;IACrB,CAAC;AACL,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAkB,EAAE,aAAuB;IACxE,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACnE,OAAO,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACxC,OAAO,CACH,oBAAC,IAAI,IACD,GAAG,EAAE,MAAM,CAAC,IAAI,EAChB,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,GAChC,CACL,CAAC;IACN,CAAC;IACD,OAAO,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;AAC9E,CAAC;AAED,IAAI,QAA4B,CAAC;AAEjC;;GAEG;AACH,MAAM,UAAU,cAAc;AAC1B,wBAAwB;AACxB,IAAiC,EACjC,aAAuB;IAEvB,QAAQ,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;IAEhC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;IACrC,CAAC;IAED,OAAO,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,IAA6C;IACjE,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,QAAQ,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;IACrC,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC","sourcesContent":["import React from 'react';\n\nimport type { ActionBase, ControlBase, IndicatorColor } from './protocol/api';\nimport {\n Add,\n Article,\n BatteryAlert,\n BatteryChargingFull,\n BatteryFull,\n Bluetooth,\n BluetoothDisabled,\n Delete,\n Edit,\n FastForward,\n FastRewind,\n Fluorescent,\n Group,\n Info,\n Lightbulb,\n Link as LinkIcon,\n LinkOff,\n NotListedLocation,\n Pause,\n Person,\n PlayArrow,\n Power,\n QrCode,\n QuestionMark,\n Refresh,\n Search,\n Settings,\n Stop,\n Visibility,\n Upgrade,\n WbIncandescent,\n Wifi,\n WifiOff,\n Launch,\n} from '@mui/icons-material';\n\nimport { I18n, Icon, type IobTheme } from '@iobroker/gui-components';\n\n/**\n * Get Icon by font-awesome name. Do not use these names, use names from getIconByName\n *\n * @param icon font-awesome icon name\n * Only following font-awesome icons are supported:\n * - fa-trash-can, fa-trash\n * - fa-pen\n * - fa-redo-alt\n * - fa-plus\n * - fa-qrcode, qrcode\n * - fa-wifi\n * - fa-wifi-slash\n * - fa-bluetooth\n * - fa-bluetooth-slash\n * - fa-eye\n * - fa-search\n * - fa-unlink\n * - fa-link\n * - fa-search-location\n * - fa-play\n * - fa-stop\n * - fa-pause\n * @param color color of the icon\n */\nfunction getFaIcon(icon: string, color?: string): React.JSX.Element | null {\n const iconStyle = icon\n .split(' ')\n .map(s => s.trim())\n .filter(s => s !== 'fa-solid');\n\n if (iconStyle.includes('fa-trash-can') || iconStyle.includes('fa-trash')) {\n return <Delete style={{ color }} />;\n }\n if (iconStyle.includes('fa-pen')) {\n return <Edit style={{ color }} />;\n }\n if (iconStyle.includes('fa-redo-alt')) {\n return <Refresh style={{ color }} />;\n }\n if (iconStyle.includes('fa-plus')) {\n return <Add style={{ color }} />;\n }\n if (iconStyle.includes('fa-qrcode') || iconStyle.includes('qrcode')) {\n return <QrCode style={{ color }} />;\n }\n if (iconStyle.includes('fa-wifi')) {\n return <Wifi style={{ color }} />;\n }\n if (iconStyle.includes('fa-wifi-slash')) {\n return <WifiOff style={{ color }} />;\n }\n if (iconStyle.includes('fa-bluetooth')) {\n return <Bluetooth style={{ color }} />;\n }\n if (iconStyle.includes('fa-bluetooth-slash')) {\n return <BluetoothDisabled style={{ color }} />;\n }\n if (iconStyle.includes('fa-eye')) {\n return <Visibility style={{ color }} />;\n }\n if (iconStyle.includes('fa-search')) {\n return <Search style={{ color }} />;\n }\n if (iconStyle.includes('fa-unlink')) {\n return <LinkOff style={{ color }} />;\n }\n if (iconStyle.includes('fa-link')) {\n return <LinkIcon style={{ color }} />;\n }\n if (iconStyle.includes('fa-search-location')) {\n return <NotListedLocation style={{ color }} />;\n }\n if (iconStyle.includes('fa-play')) {\n return <PlayArrow style={{ color }} />;\n }\n if (iconStyle.includes('fa-stop')) {\n return <Stop style={{ color }} />;\n }\n if (iconStyle.includes('fa-pause')) {\n return <Pause style={{ color }} />;\n }\n return <QuestionMark style={{ color }} />;\n}\n\n/**\n * Get Icon by name or by action\n *\n * @param name action name\n * possible action or icon names are\n * - edit, rename\n * - delete\n * - refresh\n * - newDevice, new, add\n * - discover, search\n * - unpairDevice, unpair\n * - pairDevice, pair\n * - identify\n * - play\n * - stop\n * - pause\n * - forward, next\n * - rewind, previous\n * - lamp, light\n * - backlight\n * - dimmer\n * - socket\n * - settings\n * - users, group\n * - user\n * - qrcode\n * - identify\n * - info\n * - lines\n * - battery\n * - batteryLow, batteryAlert\n * - batteryCharging\n * @param altName icon name\n * @param color color of the icon\n * @param noDefaultIcon if true, no \"question mark\" icon will be returned for unknown names\n */\nfunction getIconByName(\n name: string,\n altName?: string,\n color?: string,\n noDefaultIcon?: boolean,\n): React.JSX.Element | null {\n if (name === 'edit' || name === 'rename' || altName === 'edit' || altName === 'rename') {\n return <Edit style={{ color }} />;\n }\n if (name === 'delete' || altName === 'delete') {\n return <Delete style={{ color }} />;\n }\n if (name === 'refresh' || altName === 'refresh') {\n return <Refresh style={{ color }} />;\n }\n if (\n name === 'newDevice' ||\n name === 'new' ||\n name === 'add' ||\n altName === 'newDevice' ||\n altName === 'new' ||\n altName === 'add'\n ) {\n return <Add style={{ color }} />;\n }\n if (name === 'discover' || name === 'search' || altName === 'discover' || altName === 'search') {\n return <Search style={{ color }} />;\n }\n if (name === 'unpairDevice' || name === 'unpair' || altName === 'unpairDevice' || altName === 'unpair') {\n return <LinkOff style={{ color }} />;\n }\n if (name === 'pairDevice' || name === 'pair' || altName === 'pairDevice' || altName === 'pair') {\n return <LinkIcon style={{ color }} />;\n }\n if (name === 'identify' || altName === 'identify') {\n return <NotListedLocation style={{ color }} />;\n }\n if (name === 'play' || altName === 'play') {\n return <PlayArrow style={{ color }} />;\n }\n if (name === 'stop' || altName === 'stop') {\n return <Stop style={{ color }} />;\n }\n if (name === 'pause' || altName === 'pause') {\n return <Pause style={{ color }} />;\n }\n if (name === 'forward' || name === 'next' || altName === 'forward' || altName === 'next') {\n return <FastForward style={{ color }} />;\n }\n if (name === 'rewind' || name === 'previous' || altName === 'rewind' || altName === 'previous') {\n return <FastRewind style={{ color }} />;\n }\n if (name === 'lamp' || name === 'light' || altName === 'lamp' || altName === 'light') {\n return <Lightbulb style={{ color }} />;\n }\n if (name === 'backlight' || altName === 'backlight') {\n return <Fluorescent style={{ color }} />;\n }\n if (name === 'dimmer' || altName === 'dimmer') {\n return <WbIncandescent style={{ color }} />;\n }\n if (name === 'socket' || altName === 'socket') {\n return <Power style={{ color }} />;\n }\n if (name === 'settings' || altName === 'settings') {\n return <Settings style={{ color }} />;\n }\n if (name === 'users' || name === 'group' || altName === 'users' || altName === 'group') {\n return <Group style={{ color }} />;\n }\n if (name === 'user' || altName === 'user') {\n return <Person style={{ color }} />;\n }\n if (name === 'update' || altName === 'update') {\n return <Upgrade style={{ color }} />;\n }\n if (name === 'qrcode' || altName === 'qrcode') {\n return <QrCode style={{ color }} />;\n }\n if (name === 'info' || altName === 'info') {\n return <Info style={{ color }} />;\n }\n if (name === 'lines' || altName === 'lines') {\n return <Article style={{ color }} />;\n }\n if (name === 'web' || altName === 'web') {\n return <Launch style={{ color }} />;\n }\n if (name === 'battery' || altName === 'battery') {\n return <BatteryFull style={{ color }} />;\n }\n if (name === 'batteryLow' || name === 'batteryAlert' || altName === 'batteryLow' || altName === 'batteryAlert') {\n return <BatteryAlert style={{ color }} />;\n }\n if (name === 'batteryCharging' || altName === 'batteryCharging') {\n return <BatteryChargingFull style={{ color }} />;\n }\n if (noDefaultIcon) {\n return null;\n }\n return <QuestionMark style={{ color }} />;\n}\n\nexport function renderControlIcon(\n action: ControlBase,\n colors?: { primary: string; secondary: string },\n value?: string | number | boolean | null,\n noDefaultIcon?: boolean,\n): React.JSX.Element | null {\n if (!action) {\n return null;\n }\n\n let color = (value && action.colorOn) || action.color || (action.state ? 'primary' : 'inherit');\n\n if (colors) {\n if (color === 'primary') {\n color = colors.primary;\n } else if (color === 'secondary') {\n color = colors.secondary;\n }\n }\n\n if (action.icon?.startsWith('fa-') || action.icon?.startsWith('fas')) {\n return getFaIcon(action.icon, color);\n }\n if (value && action.iconOn?.startsWith('data:image')) {\n return (\n <Icon\n src={action.iconOn}\n style={{ color }}\n />\n );\n }\n if (action.icon?.startsWith('data:image')) {\n return (\n <Icon\n src={action.icon}\n style={{ color }}\n />\n );\n }\n if (!noDefaultIcon) {\n return getIconByName(action.id, action.icon, color);\n }\n return null;\n}\n\n/**\n * Render an icon that is given as a plain name (and not as a part of an action or control)\n *\n * @param icon `fa-*` name, `data:image/...` string, URL or one of the names supported by `getIconByName`\n * @param color color of the icon\n * @param noDefaultIcon if true, no \"question mark\" icon will be returned for unknown or missing names\n */\nexport function renderIcon(icon?: string, color?: string, noDefaultIcon?: boolean): React.JSX.Element | null {\n if (!icon) {\n return noDefaultIcon ? null : <QuestionMark style={{ color }} />;\n }\n if (icon.startsWith('fa-') || icon.startsWith('fas')) {\n return getFaIcon(icon, color);\n }\n if (\n icon.startsWith('data:image') ||\n icon.startsWith('http://') ||\n icon.startsWith('https://') ||\n icon.includes('/') ||\n /\\.(png|jpe?g|svg|gif|webp|ico)$/i.test(icon)\n ) {\n return (\n <Icon\n src={icon}\n style={{ color }}\n />\n );\n }\n return getIconByName(icon, undefined, color, noDefaultIcon);\n}\n\n/**\n * Resolve the color of a status indicator.\n *\n * The semantic tokens use the same colors as the built-in status icons, but adapted to the theme,\n * so custom indicators do not look foreign next to connection, battery, warning and update.\n *\n * @param color semantic token, `primary`, `secondary` or an explicit CSS color\n * @param theme current theme\n */\nexport function getIndicatorColor(color: IndicatorColor | undefined, theme: IobTheme): string | undefined {\n if (!color) {\n return undefined;\n }\n const dark = theme.palette.mode === 'dark';\n\n switch (color) {\n case 'ok':\n return dark ? '#5cff5c' : '#00ac00';\n case 'warning':\n return dark ? '#ffa733' : '#da8200';\n case 'error':\n return dark ? '#ff5c5c' : '#ff0000';\n case 'info':\n return dark ? '#64b5f6' : '#2196f3';\n case 'inactive':\n return '#8a8a8a';\n case 'primary':\n return theme.palette.primary.main;\n case 'secondary':\n return theme.palette.secondary.main;\n default:\n return color;\n }\n}\n\nexport function renderActionIcon(action: ActionBase, noDefaultIcon?: boolean): React.JSX.Element | null {\n if (!action) {\n return null;\n }\n\n if (action.icon?.startsWith('fa-') || action.icon?.startsWith('fas')) {\n return getFaIcon(action.icon, action.color);\n }\n if (action.icon?.startsWith('data:image')) {\n return (\n <Icon\n src={action.icon}\n style={{ color: action.color }}\n />\n );\n }\n return getIconByName(action.id, action.icon, action.color, noDefaultIcon);\n}\n\nlet language: ioBroker.Languages;\n\n/**\n * Get Translation\n */\nexport function getTranslation(\n /** Text to translate */\n text: ioBroker.StringOrTranslated,\n noTranslation?: boolean,\n): string {\n language ||= I18n.getLanguage();\n\n if (typeof text === 'object') {\n return text[language] || text.en;\n }\n\n return noTranslation ? text : I18n.t(text);\n}\n\n/**\n * Resolve a possibly translated text into the current language.\n *\n * Unlike `getTranslation`, a plain string is returned untouched: device names, models and\n * manufacturers are data, not keys of the i18n dictionary.\n */\nexport function getText(text: ioBroker.StringOrTranslated | undefined): string | undefined {\n if (typeof text === 'object') {\n language ||= I18n.getLanguage();\n return text[language] || text.en;\n }\n\n return text;\n}\n"]}
|
package/build/hooks.js
CHANGED
|
@@ -2,9 +2,28 @@ import { useEffect, useState } from 'react';
|
|
|
2
2
|
export function useStateOrObject(item, stateOrObjectHandler) {
|
|
3
3
|
const [value, setValue] = useState();
|
|
4
4
|
useEffect(() => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
// `addListener` is asynchronous. If the effect is cleaned up before it settles, `subscription`
|
|
6
|
+
// is still undefined and the plain `subscription?.unsubscribe()` of a naive cleanup would leak
|
|
7
|
+
// the socket subscription and keep calling `setValue` on an unmounted component. The flag makes
|
|
8
|
+
// both cases safe: the value is dropped and the late subscription is unsubscribed at once.
|
|
9
|
+
let cancelled = false;
|
|
10
|
+
let subscription;
|
|
11
|
+
void stateOrObjectHandler
|
|
12
|
+
.addListener(item, newValue => {
|
|
13
|
+
if (!cancelled) {
|
|
14
|
+
setValue(newValue);
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
.then(sub => {
|
|
18
|
+
subscription = sub;
|
|
19
|
+
if (cancelled) {
|
|
20
|
+
void sub.unsubscribe();
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return () => {
|
|
24
|
+
cancelled = true;
|
|
25
|
+
void subscription?.unsubscribe();
|
|
26
|
+
};
|
|
8
27
|
}, [stateOrObjectHandler, item]);
|
|
9
28
|
return value;
|
|
10
29
|
}
|
package/build/hooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","sourceRoot":"./src/","sources":["hooks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAG5C,MAAM,UAAU,gBAAgB,CAC5B,IAAyC,EACzC,oBAA0C;IAE1C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,EAAK,CAAC;IAExC,SAAS,CAAC,GAAG,EAAE;QACX,
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"./src/","sources":["hooks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAG5C,MAAM,UAAU,gBAAgB,CAC5B,IAAyC,EACzC,oBAA0C;IAE1C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,EAAK,CAAC;IAExC,SAAS,CAAC,GAAG,EAAE;QACX,+FAA+F;QAC/F,+FAA+F;QAC/F,gGAAgG;QAChG,2FAA2F;QAC3F,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,IAAI,YAAmD,CAAC;QAExD,KAAK,oBAAoB;aACpB,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE;YAC1B,IAAI,CAAC,SAAS,EAAE,CAAC;gBACb,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;QACL,CAAC,CAAC;aACD,IAAI,CAAC,GAAG,CAAC,EAAE;YACR,YAAY,GAAG,GAAG,CAAC;YACnB,IAAI,SAAS,EAAE,CAAC;gBACZ,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;YAC3B,CAAC;QACL,CAAC,CAAC,CAAC;QAEP,OAAO,GAAG,EAAE;YACR,SAAS,GAAG,IAAI,CAAC;YACjB,KAAK,YAAY,EAAE,WAAW,EAAE,CAAC;QACrC,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC,CAAC;IAEjC,OAAO,KAAK,CAAC;AACjB,CAAC","sourcesContent":["import type { ValueOrStateOrObject } from '@iobroker/dm-utils';\nimport { useEffect, useState } from 'react';\nimport type { StateOrObjectHandler, StateOrObjectSubscription } from './StateOrObjectHandler';\n\nexport function useStateOrObject<T extends ioBroker.StringOrTranslated | number | boolean>(\n item: ValueOrStateOrObject<T> | undefined,\n stateOrObjectHandler: StateOrObjectHandler,\n): T | undefined {\n const [value, setValue] = useState<T>();\n\n useEffect(() => {\n // `addListener` is asynchronous. If the effect is cleaned up before it settles, `subscription`\n // is still undefined and the plain `subscription?.unsubscribe()` of a naive cleanup would leak\n // the socket subscription and keep calling `setValue` on an unmounted component. The flag makes\n // both cases safe: the value is dropped and the late subscription is unsubscribed at once.\n let cancelled = false;\n let subscription: StateOrObjectSubscription | undefined;\n\n void stateOrObjectHandler\n .addListener(item, newValue => {\n if (!cancelled) {\n setValue(newValue);\n }\n })\n .then(sub => {\n subscription = sub;\n if (cancelled) {\n void sub.unsubscribe();\n }\n });\n\n return () => {\n cancelled = true;\n void subscription?.unsubscribe();\n };\n }, [stateOrObjectHandler, item]);\n\n return value;\n}\n"]}
|
package/build/i18n/de.json
CHANGED
package/build/i18n/en.json
CHANGED
package/build/i18n/es.json
CHANGED