iobroker.devices 2.0.16 → 2.0.18

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.
Files changed (100) hide show
  1. package/README.md +1 -1
  2. package/admin/assets/{index-BYWrx6p6.js → index-C_YA-yey.js} +153 -153
  3. package/admin/assets/{index-BxArWwbd.js → index-QGU5trgB.js} +1 -1
  4. package/admin/index_m.html +1 -1
  5. package/admin/src-admin/src/App.js +5 -5
  6. package/admin/src-admin/src/App.js.map +1 -1
  7. package/admin/tab.html +1 -1
  8. package/build/lib/WidgetsManagement.js +3 -7
  9. package/build/lib/WidgetsManagement.js.map +1 -1
  10. package/io-package.json +2 -2
  11. package/package.json +5 -2
  12. package/packages/dm-widgets/build/StateContext.d.ts +54 -0
  13. package/packages/dm-widgets/build/StateContext.d.ts.map +1 -0
  14. package/{build/packages/dm-widgets/src → packages/dm-widgets/build}/StateContext.js +11 -16
  15. package/packages/dm-widgets/build/WidgetGeneric.d.ts +181 -0
  16. package/packages/dm-widgets/build/WidgetGeneric.d.ts.map +1 -0
  17. package/{build/packages/dm-widgets/src → packages/dm-widgets/build}/WidgetGeneric.js +9 -13
  18. package/packages/dm-widgets/build/index.d.ts +55 -0
  19. package/packages/dm-widgets/build/index.d.ts.map +1 -0
  20. package/packages/dm-widgets/build/index.js +59 -0
  21. package/packages/dm-widgets/build/types.d.ts +133 -0
  22. package/packages/dm-widgets/build/types.d.ts.map +1 -0
  23. package/packages/dm-widgets/build/types.js +1 -0
  24. package/packages/dm-widgets/package-lock.json +2753 -0
  25. package/packages/dm-widgets/package.json +43 -0
  26. package/www/assets/{index-DrgD6__K.js → index-DEPE9oow.js} +4 -4
  27. package/www/assets/{index-8ywZEZX-.js → index-DLKwoafV.js} +1 -1
  28. package/www/index.html +1 -1
  29. package/admin/src-admin/src/WidgetsManager/Widgets/ColorLight.js +0 -643
  30. package/admin/src-admin/src/WidgetsManager/Widgets/ColorLight.js.map +0 -1
  31. package/admin/src-admin/src/WidgetsManager/Widgets/ColorLightDialog.js +0 -165
  32. package/admin/src-admin/src/WidgetsManager/Widgets/ColorLightDialog.js.map +0 -1
  33. package/admin/src-admin/src/WidgetsManager/Widgets/Dimmer.js +0 -563
  34. package/admin/src-admin/src/WidgetsManager/Widgets/Dimmer.js.map +0 -1
  35. package/admin/src-admin/src/WidgetsManager/Widgets/Door.js +0 -34
  36. package/admin/src-admin/src/WidgetsManager/Widgets/Door.js.map +0 -1
  37. package/admin/src-admin/src/WidgetsManager/Widgets/EnergyFlow.js +0 -1307
  38. package/admin/src-admin/src/WidgetsManager/Widgets/EnergyFlow.js.map +0 -1
  39. package/admin/src-admin/src/WidgetsManager/Widgets/FireAlarm.js +0 -143
  40. package/admin/src-admin/src/WidgetsManager/Widgets/FireAlarm.js.map +0 -1
  41. package/admin/src-admin/src/WidgetsManager/Widgets/FloodAlarm.js +0 -143
  42. package/admin/src-admin/src/WidgetsManager/Widgets/FloodAlarm.js.map +0 -1
  43. package/admin/src-admin/src/WidgetsManager/Widgets/Gate.js +0 -251
  44. package/admin/src-admin/src/WidgetsManager/Widgets/Gate.js.map +0 -1
  45. package/admin/src-admin/src/WidgetsManager/Widgets/Gauge.js +0 -544
  46. package/admin/src-admin/src/WidgetsManager/Widgets/Gauge.js.map +0 -1
  47. package/admin/src-admin/src/WidgetsManager/Widgets/Humidity.js +0 -140
  48. package/admin/src-admin/src/WidgetsManager/Widgets/Humidity.js.map +0 -1
  49. package/admin/src-admin/src/WidgetsManager/Widgets/Iframe.js +0 -237
  50. package/admin/src-admin/src/WidgetsManager/Widgets/Iframe.js.map +0 -1
  51. package/admin/src-admin/src/WidgetsManager/Widgets/Illuminance.js +0 -104
  52. package/admin/src-admin/src/WidgetsManager/Widgets/Illuminance.js.map +0 -1
  53. package/admin/src-admin/src/WidgetsManager/Widgets/Image.js +0 -269
  54. package/admin/src-admin/src/WidgetsManager/Widgets/Image.js.map +0 -1
  55. package/admin/src-admin/src/WidgetsManager/Widgets/Info.js +0 -290
  56. package/admin/src-admin/src/WidgetsManager/Widgets/Info.js.map +0 -1
  57. package/admin/src-admin/src/WidgetsManager/Widgets/Light.js +0 -19
  58. package/admin/src-admin/src/WidgetsManager/Widgets/Light.js.map +0 -1
  59. package/admin/src-admin/src/WidgetsManager/Widgets/Location.js +0 -681
  60. package/admin/src-admin/src/WidgetsManager/Widgets/Location.js.map +0 -1
  61. package/admin/src-admin/src/WidgetsManager/Widgets/Lock.js +0 -282
  62. package/admin/src-admin/src/WidgetsManager/Widgets/Lock.js.map +0 -1
  63. package/admin/src-admin/src/WidgetsManager/Widgets/MediaPlayer.js +0 -635
  64. package/admin/src-admin/src/WidgetsManager/Widgets/MediaPlayer.js.map +0 -1
  65. package/admin/src-admin/src/WidgetsManager/Widgets/Motion.js +0 -202
  66. package/admin/src-admin/src/WidgetsManager/Widgets/Motion.js.map +0 -1
  67. package/admin/src-admin/src/WidgetsManager/Widgets/Slider.js +0 -658
  68. package/admin/src-admin/src/WidgetsManager/Widgets/Slider.js.map +0 -1
  69. package/admin/src-admin/src/WidgetsManager/Widgets/Switch.js +0 -89
  70. package/admin/src-admin/src/WidgetsManager/Widgets/Switch.js.map +0 -1
  71. package/admin/src-admin/src/WidgetsManager/Widgets/Tank.js +0 -432
  72. package/admin/src-admin/src/WidgetsManager/Widgets/Tank.js.map +0 -1
  73. package/admin/src-admin/src/WidgetsManager/Widgets/Temperature.js +0 -162
  74. package/admin/src-admin/src/WidgetsManager/Widgets/Temperature.js.map +0 -1
  75. package/admin/src-admin/src/WidgetsManager/Widgets/Window.js +0 -148
  76. package/admin/src-admin/src/WidgetsManager/Widgets/Window.js.map +0 -1
  77. package/build/lib/DeviceManagement.js +0 -618
  78. package/build/lib/DeviceManagement.js.map +0 -1
  79. package/build/packages/dm-widgets/src/StateContext.js.map +0 -1
  80. package/build/packages/dm-widgets/src/WidgetGeneric.js.map +0 -1
  81. package/build/packages/dm-widgets/src/index.js +0 -99
  82. package/build/packages/dm-widgets/src/index.js.map +0 -1
  83. package/build/packages/dm-widgets/src/types.js +0 -3
  84. package/build/packages/dm-widgets/src/types.js.map +0 -1
  85. package/build/src/lib/WidgetsManagement.js +0 -756
  86. package/build/src/lib/WidgetsManagement.js.map +0 -1
  87. package/build/src/main.js +0 -53
  88. package/build/src/main.js.map +0 -1
  89. package/build/src/widget-utils/WidgetsManagement.js +0 -119
  90. package/build/src/widget-utils/WidgetsManagement.js.map +0 -1
  91. package/build/src/widget-utils/index.js +0 -18
  92. package/build/src/widget-utils/index.js.map +0 -1
  93. package/build/src/widget-utils/types/api.js +0 -3
  94. package/build/src/widget-utils/types/api.js.map +0 -1
  95. package/build/src/widget-utils/types/base.js +0 -3
  96. package/build/src/widget-utils/types/base.js.map +0 -1
  97. package/build/src/widget-utils/types/index.js +0 -3
  98. package/build/src/widget-utils/types/index.js.map +0 -1
  99. package/build/widget-utils/types/common.js +0 -3
  100. package/build/widget-utils/types/common.js.map +0 -1
@@ -1,643 +0,0 @@
1
- import React from 'react';
2
- import { Box, Slider, Switch as MuiSwitch, Tooltip, Typography } from '@mui/material';
3
- import { LightbulbOutlined } from '@mui/icons-material';
4
- import { I18n } from '@iobroker/adapter-react-v5';
5
- import { Types } from '@iobroker/type-detector';
6
- import WidgetGeneric, { getTileStyles, isNeumorphicTheme, } from './Generic';
7
- import { hexToRgb, rgbToHex, hsvToRgb, rgbToHsv, ctToRgb, rgbToCie, cieToRgb } from './colorUtils';
8
- import ColorLightDialog from './ColorLightDialog';
9
- // --- Widget ---
10
- export class WidgetColorLight extends WidgetGeneric {
11
- // Dimmer states
12
- setId;
13
- actualId;
14
- onSetId;
15
- onActualId;
16
- // Color states — filled per subtype
17
- rgbId; // rgbSingle: RGB string
18
- rgbwId; // rgbwSingle: RGBW string
19
- redId; // rgb: separate channels
20
- greenId;
21
- blueId;
22
- whiteId;
23
- hueId; // hue type
24
- saturationId;
25
- ctId; // color temperature
26
- cieId; // CIE xy string
27
- arcRef = React.createRef();
28
- dragStartPos = null;
29
- isDragging = false;
30
- longPressTimer = null;
31
- longPressTriggered = false;
32
- constructor(props) {
33
- super(props);
34
- const states = props.widget.control.states;
35
- const find = (name) => states.find(s => s.name === name)?.id ?? null;
36
- // Dimmer
37
- const set = find('SET');
38
- const actual = find('ACTUAL');
39
- this.setId = set;
40
- this.actualId = actual ?? set;
41
- this.onSetId = find('ON_SET') ?? find('ON');
42
- this.onActualId = find('ON_ACTUAL') ?? this.onSetId;
43
- // Color — all optional, availability depends on device type
44
- this.rgbId = find('RGB');
45
- this.rgbwId = find('RGBW');
46
- this.redId = find('RED');
47
- this.greenId = find('GREEN');
48
- this.blueId = find('BLUE');
49
- this.whiteId = find('WHITE');
50
- this.hueId = find('HUE');
51
- this.saturationId = find('SATURATION');
52
- this.ctId = find('TEMPERATURE');
53
- this.cieId = find('CIE');
54
- // Dimmer may not exist for some pure-color types
55
- const dimmer = find('DIMMER') ?? find('BRIGHTNESS');
56
- if (dimmer) {
57
- if (!this.setId) {
58
- this.setId = dimmer;
59
- }
60
- if (!this.actualId) {
61
- this.actualId = dimmer;
62
- }
63
- }
64
- this.state = {
65
- ...this.state,
66
- brightness: 0,
67
- isOn: false,
68
- dragging: false,
69
- dimMin: 0,
70
- dimMax: 100,
71
- color: '#ffffff',
72
- dialogOpen: false,
73
- ctValue: 4000,
74
- ctMin: 2000,
75
- ctMax: 6500,
76
- };
77
- }
78
- static getDefaultSettings() {
79
- return {
80
- ...WidgetGeneric.getDefaultSettings(),
81
- onBrightness: 100,
82
- };
83
- }
84
- static getConfigSchema() {
85
- return {
86
- name: 'Image settings', // ignored
87
- schema: {
88
- type: 'panel',
89
- items: {
90
- onBrightness: {
91
- type: 'number',
92
- label: 'wm_On brightness',
93
- default: 100,
94
- min: 1,
95
- max: 100,
96
- unit: '%',
97
- },
98
- },
99
- },
100
- };
101
- }
102
- // --- Lifecycle ---
103
- componentDidMount() {
104
- super.componentDidMount();
105
- if (this.actualId) {
106
- this.props.stateContext.getState(this.actualId, this.onBrightnessChange);
107
- }
108
- if (this.onActualId && this.onActualId !== this.actualId) {
109
- this.props.stateContext.getState(this.onActualId, this.onOnOffChange);
110
- }
111
- // Color subscriptions
112
- if (this.rgbId) {
113
- this.props.stateContext.getState(this.rgbId, this.onRgbChange);
114
- }
115
- if (this.rgbwId) {
116
- this.props.stateContext.getState(this.rgbwId, this.onRgbwChange);
117
- }
118
- if (this.redId) {
119
- this.props.stateContext.getState(this.redId, this.onChannelChange);
120
- }
121
- if (this.greenId) {
122
- this.props.stateContext.getState(this.greenId, this.onChannelChange);
123
- }
124
- if (this.blueId) {
125
- this.props.stateContext.getState(this.blueId, this.onChannelChange);
126
- }
127
- if (this.hueId) {
128
- this.props.stateContext.getState(this.hueId, this.onHsvChange);
129
- }
130
- if (this.saturationId) {
131
- this.props.stateContext.getState(this.saturationId, this.onHsvChange);
132
- }
133
- if (this.ctId) {
134
- this.props.stateContext.getState(this.ctId, this.onCtChange);
135
- }
136
- if (this.cieId) {
137
- this.props.stateContext.getState(this.cieId, this.onCieChange);
138
- }
139
- void this.loadDimmerObject();
140
- void this.loadCtObject();
141
- }
142
- componentWillUnmount() {
143
- super.componentWillUnmount();
144
- if (this.longPressTimer) {
145
- clearTimeout(this.longPressTimer);
146
- this.longPressTimer = null;
147
- }
148
- if (this.actualId) {
149
- this.props.stateContext.removeState(this.actualId, this.onBrightnessChange);
150
- }
151
- if (this.onActualId && this.onActualId !== this.actualId) {
152
- this.props.stateContext.removeState(this.onActualId, this.onOnOffChange);
153
- }
154
- if (this.rgbId) {
155
- this.props.stateContext.removeState(this.rgbId, this.onRgbChange);
156
- }
157
- if (this.rgbwId) {
158
- this.props.stateContext.removeState(this.rgbwId, this.onRgbwChange);
159
- }
160
- if (this.redId) {
161
- this.props.stateContext.removeState(this.redId, this.onChannelChange);
162
- }
163
- if (this.greenId) {
164
- this.props.stateContext.removeState(this.greenId, this.onChannelChange);
165
- }
166
- if (this.blueId) {
167
- this.props.stateContext.removeState(this.blueId, this.onChannelChange);
168
- }
169
- if (this.hueId) {
170
- this.props.stateContext.removeState(this.hueId, this.onHsvChange);
171
- }
172
- if (this.saturationId) {
173
- this.props.stateContext.removeState(this.saturationId, this.onHsvChange);
174
- }
175
- if (this.ctId) {
176
- this.props.stateContext.removeState(this.ctId, this.onCtChange);
177
- }
178
- if (this.cieId) {
179
- this.props.stateContext.removeState(this.cieId, this.onCieChange);
180
- }
181
- }
182
- // --- Object loaders ---
183
- async loadDimmerObject() {
184
- const id = this.setId || this.actualId;
185
- if (!id) {
186
- return;
187
- }
188
- try {
189
- const obj = (await this.props.stateContext.getSocket().getObject(id));
190
- if (obj?.common) {
191
- const min = obj.common.min != null ? Number(obj.common.min) : 0;
192
- const max = obj.common.max != null ? Number(obj.common.max) : 100;
193
- if (!isNaN(min) && !isNaN(max) && max > min) {
194
- this.setState({ dimMin: min, dimMax: max });
195
- }
196
- }
197
- }
198
- catch {
199
- // ignore
200
- }
201
- }
202
- async loadCtObject() {
203
- if (!this.ctId) {
204
- return;
205
- }
206
- try {
207
- const obj = (await this.props.stateContext.getSocket().getObject(this.ctId));
208
- if (obj?.common) {
209
- const min = obj.common.min != null ? Number(obj.common.min) : 2000;
210
- const max = obj.common.max != null ? Number(obj.common.max) : 6500;
211
- if (!isNaN(min) && !isNaN(max) && max > min) {
212
- this.setState({ ctMin: min, ctMax: max });
213
- }
214
- }
215
- }
216
- catch {
217
- // ignore
218
- }
219
- }
220
- rawToPercent(raw) {
221
- const { dimMin, dimMax } = this.state;
222
- const range = dimMax - dimMin;
223
- if (range <= 0) {
224
- return 0;
225
- }
226
- return Math.round(((raw - dimMin) / range) * 100);
227
- }
228
- percentToRaw(percent) {
229
- const { dimMin, dimMax } = this.state;
230
- return dimMin + (percent / 100) * (dimMax - dimMin);
231
- }
232
- // --- State change callbacks ---
233
- onBrightnessChange = (_id, state) => {
234
- if (this.isDragging) {
235
- return;
236
- }
237
- const raw = Number(state.val) || 0;
238
- const brightness = this.rawToPercent(raw);
239
- if (brightness !== this.state.brightness) {
240
- if (!this.onActualId || this.onActualId === this.actualId) {
241
- this.setState({ brightness, isOn: brightness > 0 });
242
- }
243
- else {
244
- this.setState({ brightness });
245
- }
246
- }
247
- };
248
- onOnOffChange = (_id, state) => {
249
- const isOn = !!state.val;
250
- if (isOn !== this.state.isOn) {
251
- this.setState({ isOn });
252
- }
253
- };
254
- // --- Color state callbacks ---
255
- /** Raw channel values for RGB separate mode */
256
- channelValues = { r: 0, g: 0, b: 0 };
257
- onRgbChange = (_id, state) => {
258
- const val = String(state.val || '').replace(/^#/, '');
259
- if (val.length >= 6) {
260
- this.setState({ color: `#${val.slice(0, 6)}` });
261
- }
262
- };
263
- onRgbwChange = (_id, state) => {
264
- // RGBW: take first 6 hex chars as RGB
265
- const val = String(state.val || '').replace(/^#/, '');
266
- if (val.length >= 6) {
267
- this.setState({ color: `#${val.slice(0, 6)}` });
268
- }
269
- };
270
- onChannelChange = (id, state) => {
271
- const val = Math.round(Number(state.val) || 0);
272
- if (id === this.redId) {
273
- this.channelValues.r = val;
274
- }
275
- else if (id === this.greenId) {
276
- this.channelValues.g = val;
277
- }
278
- else if (id === this.blueId) {
279
- this.channelValues.b = val;
280
- }
281
- const { r, g, b } = this.channelValues;
282
- this.setState({ color: rgbToHex(r, g, b) });
283
- };
284
- /** Hue/saturation raw values */
285
- hsvValues = { h: 0, s: 100 };
286
- onHsvChange = (id, state) => {
287
- const val = Number(state.val) || 0;
288
- if (id === this.hueId) {
289
- this.hsvValues.h = val;
290
- }
291
- else if (id === this.saturationId) {
292
- this.hsvValues.s = val;
293
- }
294
- const [r, g, b] = hsvToRgb(this.hsvValues.h, this.hsvValues.s / 100, 1);
295
- this.setState({ color: rgbToHex(r, g, b) });
296
- };
297
- onCtChange = (_id, state) => {
298
- const kelvin = Number(state.val) || 4000;
299
- const [r, g, b] = ctToRgb(kelvin);
300
- this.setState({ color: rgbToHex(r, g, b), ctValue: kelvin });
301
- };
302
- onCieChange = (_id, state) => {
303
- const val = String(state.val || '');
304
- const parts = val.split(',').map(Number);
305
- if (parts.length >= 2 && !isNaN(parts[0]) && !isNaN(parts[1])) {
306
- const [r, g, b] = cieToRgb(parts[0], parts[1]);
307
- this.setState({ color: rgbToHex(r, g, b) });
308
- }
309
- };
310
- // --- Send color to device ---
311
- sendColor(hex) {
312
- const type = this.props.widget.control.type;
313
- const socket = this.props.stateContext.getSocket();
314
- const [r, g, b] = hexToRgb(hex);
315
- if (type === Types.rgbSingle && this.rgbId) {
316
- void socket.setState(this.rgbId, hex.replace(/^#/, ''));
317
- }
318
- else if (type === Types.rgbwSingle && this.rgbwId) {
319
- // Keep existing white channel
320
- void socket.setState(this.rgbwId, `${hex.replace(/^#/, '')}00`);
321
- }
322
- else if (type === Types.rgb) {
323
- if (this.redId) {
324
- void socket.setState(this.redId, r);
325
- }
326
- if (this.greenId) {
327
- void socket.setState(this.greenId, g);
328
- }
329
- if (this.blueId) {
330
- void socket.setState(this.blueId, b);
331
- }
332
- }
333
- else if (type === Types.hue) {
334
- const [h, s] = rgbToHsv(r, g, b);
335
- if (this.hueId) {
336
- void socket.setState(this.hueId, Math.round(h));
337
- }
338
- if (this.saturationId) {
339
- void socket.setState(this.saturationId, Math.round(s * 100));
340
- }
341
- }
342
- else if (type === Types.cie && this.cieId) {
343
- const [cx, cy] = rgbToCie(r, g, b);
344
- void socket.setState(this.cieId, `${cx.toFixed(4)},${cy.toFixed(4)}`);
345
- }
346
- // CT is not set from RGB hex — it has its own control
347
- }
348
- // --- Dimmer controls ---
349
- toggleOnOff = () => {
350
- if (this.onSetId) {
351
- void this.props.stateContext.getSocket().setState(this.onSetId, !this.state.isOn);
352
- }
353
- else if (this.setId) {
354
- const onPercent = this.props.settings?.onBrightness ?? 100;
355
- void this.props.stateContext
356
- .getSocket()
357
- .setState(this.setId, this.state.isOn ? this.state.dimMin : this.percentToRaw(onPercent));
358
- }
359
- };
360
- onSliderChange = (_e, value) => {
361
- const percent = value;
362
- if (this.setId) {
363
- void this.props.stateContext.getSocket().setState(this.setId, this.percentToRaw(percent));
364
- }
365
- if (this.onSetId && !this.state.isOn && percent > 0) {
366
- void this.props.stateContext.getSocket().setState(this.onSetId, true);
367
- }
368
- };
369
- // --- Dialog callbacks ---
370
- hasColorControl() {
371
- const type = this.props.widget.control.type;
372
- return type !== Types.ct;
373
- }
374
- onDialogColorChange = (hex) => {
375
- this.setState({ color: hex });
376
- this.sendColor(hex);
377
- };
378
- onDialogBrightnessChange = (percent) => {
379
- this.setState({ brightness: percent, isOn: percent > 0 });
380
- if (this.setId) {
381
- void this.props.stateContext.getSocket().setState(this.setId, this.percentToRaw(percent));
382
- }
383
- if (this.onSetId && !this.state.isOn && percent > 0) {
384
- void this.props.stateContext.getSocket().setState(this.onSetId, true);
385
- }
386
- };
387
- onDialogCtChange = (kelvin) => {
388
- this.setState({ ctValue: kelvin });
389
- if (this.ctId) {
390
- void this.props.stateContext.getSocket().setState(this.ctId, kelvin);
391
- }
392
- };
393
- openDialog = () => {
394
- this.setState({ dialogOpen: true });
395
- };
396
- closeDialog = () => {
397
- this.setState({ dialogOpen: false });
398
- };
399
- // --- Arc knob ---
400
- pointerToPercent(clientX, clientY) {
401
- const el = this.arcRef.current;
402
- if (!el) {
403
- return this.state.brightness;
404
- }
405
- const rect = el.getBoundingClientRect();
406
- const cx = rect.left + rect.width / 2;
407
- const cy = rect.top + rect.height / 2;
408
- const dx = clientX - cx;
409
- const dy = clientY - cy;
410
- let angle = Math.atan2(dy, dx) * (180 / Math.PI);
411
- if (angle < 0) {
412
- angle += 360;
413
- }
414
- let normalized = angle - 135;
415
- if (normalized < 0) {
416
- normalized += 360;
417
- }
418
- if (normalized > 270) {
419
- return normalized > 315 ? 0 : 100;
420
- }
421
- return Math.round((normalized / 270) * 100);
422
- }
423
- onArcPointerDown = (e) => {
424
- e.preventDefault();
425
- e.target.setPointerCapture(e.pointerId);
426
- this.dragStartPos = { x: e.clientX, y: e.clientY };
427
- this.isDragging = false;
428
- this.longPressTriggered = false;
429
- // When power control exists (dedicated or brightness-simulated): tap = toggle, long press = dialog
430
- if (this.onSetId || this.setId) {
431
- this.longPressTimer = setTimeout(() => {
432
- this.longPressTriggered = true;
433
- this.dragStartPos = null;
434
- if (typeof navigator !== 'undefined' && 'vibrate' in navigator) {
435
- navigator.vibrate(50);
436
- }
437
- this.setState({ dialogOpen: true });
438
- }, 500);
439
- }
440
- };
441
- onArcPointerMove = (e) => {
442
- if (!this.dragStartPos) {
443
- return;
444
- }
445
- const dx = e.clientX - this.dragStartPos.x;
446
- const dy = e.clientY - this.dragStartPos.y;
447
- if (!this.isDragging && Math.sqrt(dx * dx + dy * dy) > 8) {
448
- this.isDragging = true;
449
- this.setState({ dragging: true });
450
- if (this.longPressTimer) {
451
- clearTimeout(this.longPressTimer);
452
- this.longPressTimer = null;
453
- }
454
- }
455
- if (this.isDragging) {
456
- const percent = this.pointerToPercent(e.clientX, e.clientY);
457
- this.setState({ brightness: percent, isOn: this.state.isOn || percent > 0 });
458
- }
459
- };
460
- onArcPointerUp = (e) => {
461
- if (this.longPressTimer) {
462
- clearTimeout(this.longPressTimer);
463
- this.longPressTimer = null;
464
- }
465
- if (!this.dragStartPos && !this.isDragging) {
466
- // Long press already triggered
467
- this.longPressTriggered = false;
468
- return;
469
- }
470
- if (this.isDragging) {
471
- const percent = this.pointerToPercent(e.clientX, e.clientY);
472
- if (this.setId) {
473
- void this.props.stateContext.getSocket().setState(this.setId, this.percentToRaw(percent));
474
- }
475
- if (this.onSetId && !this.state.isOn && percent > 0) {
476
- void this.props.stateContext.getSocket().setState(this.onSetId, true);
477
- }
478
- }
479
- else if (this.onSetId || this.setId) {
480
- // Tap with power control — toggle on/off
481
- this.toggleOnOff();
482
- }
483
- else {
484
- // Tap without any power control — open dialog directly
485
- this.openDialog();
486
- }
487
- this.dragStartPos = null;
488
- this.isDragging = false;
489
- this.setState({ dragging: false });
490
- };
491
- // --- Overrides ---
492
- isTileActive() {
493
- if (this.onActualId && this.onActualId !== this.actualId) {
494
- return this.state.isOn;
495
- }
496
- return this.state.brightness > 0 || this.state.isOn;
497
- }
498
- // eslint-disable-next-line class-methods-use-this
499
- hasTileAction() {
500
- return true;
501
- }
502
- onTileClick() {
503
- if (this.onSetId || this.setId) {
504
- this.toggleOnOff();
505
- }
506
- else {
507
- this.openDialog();
508
- }
509
- }
510
- renderTileIcon() {
511
- const baseIcon = this.renderBaseIcon();
512
- if (baseIcon) {
513
- return baseIcon;
514
- }
515
- const isActive = this.isTileActive();
516
- const { color, brightness } = this.state;
517
- return (React.createElement(LightbulbOutlined, { sx: theme => ({
518
- color: isActive ? color : theme.palette.text.disabled,
519
- transition: 'color 0.25s ease',
520
- filter: isActive ? `drop-shadow(0 0 ${4 + brightness / 10}px ${color})` : 'none',
521
- }) }));
522
- }
523
- renderTileStatus() {
524
- const isActive = this.isTileActive();
525
- const { color, brightness } = this.state;
526
- return (React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 } },
527
- isActive ? (React.createElement(Box, { sx: {
528
- width: 10,
529
- height: 10,
530
- borderRadius: '50%',
531
- backgroundColor: color,
532
- border: '1px solid',
533
- borderColor: 'divider',
534
- flexShrink: 0,
535
- } })) : null,
536
- React.createElement(Typography, { variant: "caption", sx: theme => ({
537
- fontWeight: 500,
538
- color: isActive ? theme.palette.text.primary : theme.palette.text.secondary,
539
- transition: 'color 0.25s ease',
540
- }) }, isActive ? `${Math.round(brightness)}%` : I18n.t('wm_Off'))));
541
- }
542
- renderTileAction() {
543
- const { brightness, color } = this.state;
544
- const accent = this.getAccentColor();
545
- return (React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
546
- React.createElement(Box, { onClick: (e) => {
547
- e.stopPropagation();
548
- this.openDialog();
549
- }, sx: {
550
- width: 24,
551
- height: 24,
552
- borderRadius: '50%',
553
- backgroundColor: color,
554
- border: '2px solid',
555
- borderColor: 'divider',
556
- cursor: 'pointer',
557
- flexShrink: 0,
558
- transition: 'background-color 0.2s ease',
559
- } }),
560
- this.setId ? (React.createElement(Slider, { value: brightness, min: 0, max: 100, size: "small", onClick: e => e.stopPropagation(), onChange: this.onSliderChange, sx: theme => ({
561
- width: 60,
562
- color: accent || theme.palette.primary.main,
563
- '& .MuiSlider-thumb': { width: 14, height: 14 },
564
- }) })) : null,
565
- this.onSetId || this.setId ? (React.createElement(MuiSwitch, { checked: this.isTileActive(), onClick: e => e.stopPropagation(), onChange: this.toggleOnOff, size: "small" })) : null));
566
- }
567
- // --- Compact (1x1): arc knob with color ring ---
568
- renderCompact() {
569
- const { name, brightness, dragging, color } = this.state;
570
- const isActive = this.isTileActive();
571
- const accent = this.getAccentColor();
572
- const settingsButton = this.renderSettingsButton();
573
- const indicators = this.renderIndicators(settingsButton);
574
- const vb = 100;
575
- const sw = 8;
576
- const r = (vb - sw) / 2;
577
- const circumference = 2 * Math.PI * r;
578
- const arcLength = circumference * 0.75;
579
- const progress = (brightness / 100) * arcLength;
580
- const arcColor = isActive ? color : 'transparent';
581
- const tile = (React.createElement(Box, { id: String(this.props.widget.id), className: this.getWidgetClass(), sx: theme => WidgetGeneric.getStyleCompact(theme) },
582
- React.createElement(Box, { ref: this.arcRef, onPointerDown: this.onArcPointerDown, onPointerMove: this.onArcPointerMove, onPointerUp: this.onArcPointerUp, onPointerCancel: this.onArcPointerUp, sx: theme => ({
583
- display: 'flex',
584
- flexDirection: 'column',
585
- justifyContent: 'space-between',
586
- alignItems: 'stretch',
587
- width: '100%',
588
- aspectRatio: '1',
589
- textAlign: 'left',
590
- overflow: 'hidden',
591
- cursor: 'pointer',
592
- touchAction: 'none',
593
- userSelect: 'none',
594
- ...getTileStyles(theme, isActive, accent),
595
- padding: isNeumorphicTheme(theme) ? 'max(12px, 8cqi)' : 'max(16px, 10cqi)',
596
- }) },
597
- indicators,
598
- React.createElement(Box, { sx: {
599
- display: 'flex',
600
- alignItems: 'center',
601
- justifyContent: 'center',
602
- position: 'relative',
603
- flex: 1,
604
- } },
605
- React.createElement("svg", { viewBox: `0 0 ${vb} ${vb}`, style: { width: '60%', height: '60%', transform: 'rotate(135deg)' } },
606
- React.createElement("circle", { cx: vb / 2, cy: vb / 2, r: r, fill: "none", stroke: "currentColor", strokeWidth: sw, strokeDasharray: `${arcLength} ${circumference}`, strokeLinecap: "round", opacity: 0.15 }),
607
- React.createElement("circle", { cx: vb / 2, cy: vb / 2, r: r, fill: "none", stroke: arcColor, strokeWidth: sw, strokeDasharray: `${progress} ${circumference}`, strokeLinecap: "round", style: dragging ? undefined : { transition: 'stroke-dasharray 0.3s ease' } })),
608
- React.createElement(Box, { sx: {
609
- position: 'absolute',
610
- display: 'flex',
611
- alignItems: 'center',
612
- justifyContent: 'center',
613
- } }, this.renderTileIcon())),
614
- React.createElement(Box, null,
615
- React.createElement(Typography, { ref: this.nameRef, variant: "body2", sx: theme => ({
616
- fontWeight: 600,
617
- lineHeight: 1.3,
618
- overflow: 'hidden',
619
- whiteSpace: 'nowrap',
620
- ...(isNeumorphicTheme(theme)
621
- ? {
622
- textTransform: 'uppercase',
623
- letterSpacing: '0.08em',
624
- fontSize: 'max(0.6rem, 6cqi)',
625
- }
626
- : {}),
627
- }) }, this.props.settings?.name || name || '...'),
628
- this.renderTileStatus()),
629
- this.renderChart())));
630
- if (this.onSetId || this.setId) {
631
- return (React.createElement(Tooltip, { title: I18n.t('wm_Long press for settings'), disableTouchListener: true, enterDelay: 500 }, tile));
632
- }
633
- return tile;
634
- }
635
- // --- Render with dialog ---
636
- render() {
637
- return (React.createElement(React.Fragment, null,
638
- super.render(),
639
- React.createElement(ColorLightDialog, { open: this.state.dialogOpen, onClose: this.closeDialog, color: this.state.color, brightness: this.state.brightness, isOn: this.state.isOn, hasColor: this.hasColorControl(), hasPower: !!(this.onSetId || this.setId), hasBrightness: !!(this.setId || this.actualId), hasCt: !!this.ctId, ctMin: this.state.ctMin, ctMax: this.state.ctMax, ctValue: this.state.ctValue, onColorChange: this.onDialogColorChange, onBrightnessChange: this.onDialogBrightnessChange, onCtChange: this.onDialogCtChange, onToggle: this.toggleOnOff })));
640
- }
641
- }
642
- export default WidgetColorLight;
643
- //# sourceMappingURL=ColorLight.js.map