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,658 +0,0 @@
1
- import React from 'react';
2
- import { Box, ButtonBase, Chip, Dialog, DialogContent, DialogTitle, Slider as MuiSlider, SvgIcon, Typography, } from '@mui/material';
3
- import { Speed, Tune } from '@mui/icons-material';
4
- import { I18n } from '@iobroker/adapter-react-v5';
5
- import WidgetGeneric, { getTileStyles, isNeumorphicTheme, } from './Generic';
6
- import { ICON_TUNE, ICON_VALVE, ICON_AIR, ICON_SPEED } from './configIcons';
7
- /** Gate valve icon with handle */
8
- function ValveIcon(props) {
9
- return (React.createElement(SvgIcon, { ...props, viewBox: "0 0 24 24" },
10
- React.createElement("rect", { x: "7", y: "2", width: "10", height: "2.5", rx: "1.25" }),
11
- React.createElement("rect", { x: "11", y: "4.5", width: "2", height: "4" }),
12
- React.createElement("path", { d: "M3,8.5 L21,8.5 L12,14 Z" }),
13
- React.createElement("path", { d: "M3,15.5 L21,15.5 L12,10 Z" }),
14
- React.createElement("rect", { x: "10", y: "15.5", width: "4", height: "6.5" })));
15
- }
16
- /** Ventilator / fan blade icon (MDI fan) */
17
- function FanIcon(props) {
18
- return (React.createElement(SvgIcon, { ...props },
19
- React.createElement("path", { d: "M12,11A1,1 0 0,0 11,12A1,1 0 0,0 12,13A1,1 0 0,0 13,12A1,1 0 0,0 12,11M12.5,2C17,2 17.11,5.57 14.75,6.75C13.76,7.24 13.32,8.29 13.13,9.22C13.61,9.42 14.03,9.73 14.35,10.13C18.05,8.13 22.03,8.92 22.03,12.5C22.03,17 18.46,17.1 17.28,14.73C16.78,13.74 15.72,13.3 14.79,13.11C14.59,13.59 14.28,14 13.88,14.34C15.87,18.03 15.08,22 11.5,22C7,22 6.91,18.42 9.27,17.24C10.25,16.75 10.69,15.71 10.89,14.79C10.4,14.59 9.97,14.27 9.65,13.87C5.96,15.85 2,15.07 2,11.5C2,7 5.56,6.89 6.74,9.26C7.24,10.25 8.29,10.68 9.22,10.87C9.41,10.39 9.73,9.97 10.14,9.65C8.15,5.96 8.94,2 12.5,2Z" })));
20
- }
21
- export class WidgetSlider extends WidgetGeneric {
22
- setId;
23
- actualId;
24
- arcRef = React.createRef();
25
- dragStartPos = null;
26
- isDragging = false;
27
- /** true when the valve vertical fill bar is shown (compact); false when arc knob is used */
28
- verticalDragMode = false;
29
- constructor(props) {
30
- super(props);
31
- const states = props.widget.control.states;
32
- const set = states.find(s => s.name === 'SET');
33
- const actual = states.find(s => s.name === 'ACTUAL');
34
- this.setId = set?.id ?? null;
35
- this.actualId = actual?.id ?? set?.id ?? null;
36
- this.state = {
37
- ...this.state,
38
- level: 0,
39
- rawValue: 0,
40
- dragging: false,
41
- rawMin: 0,
42
- rawMax: 100,
43
- unit: '%',
44
- statesMap: null,
45
- modeDialogOpen: false,
46
- };
47
- }
48
- static getDefaultSettings() {
49
- return {
50
- ...WidgetGeneric.getDefaultSettings(),
51
- sliderType: 'normal',
52
- wideSliderStyle: 'horizontal',
53
- };
54
- }
55
- static getConfigSchema() {
56
- return {
57
- name: 'Slider',
58
- schema: {
59
- type: 'panel',
60
- items: {
61
- sliderType: {
62
- type: 'select',
63
- label: 'wm_Slider type',
64
- options: [
65
- { value: 'normal', label: 'wm_slider_normal', icon: ICON_TUNE },
66
- { value: 'valve', label: 'wm_slider_valve', icon: ICON_VALVE },
67
- { value: 'fan', label: 'wm_slider_fan', icon: ICON_AIR },
68
- { value: 'gauge', label: 'wm_slider_gauge', icon: ICON_SPEED },
69
- ],
70
- default: 'normal',
71
- format: 'radio',
72
- },
73
- wideSliderStyle: {
74
- type: 'select',
75
- label: 'wm_Wide slider style',
76
- options: [
77
- { value: 'horizontal', label: 'wm_slider_horizontal' },
78
- { value: 'round', label: 'wm_slider_round' },
79
- ],
80
- default: 'horizontal',
81
- format: 'radio',
82
- hidden: "data.size === '1x1'",
83
- },
84
- },
85
- },
86
- };
87
- }
88
- componentDidMount() {
89
- super.componentDidMount();
90
- if (this.actualId) {
91
- this.props.stateContext.getState(this.actualId, this.onLevelChange);
92
- }
93
- void this.loadObjectConfig();
94
- }
95
- componentWillUnmount() {
96
- super.componentWillUnmount();
97
- if (this.actualId) {
98
- this.props.stateContext.removeState(this.actualId, this.onLevelChange);
99
- }
100
- }
101
- async loadObjectConfig() {
102
- const id = this.setId || this.actualId;
103
- if (!id) {
104
- return;
105
- }
106
- try {
107
- const obj = (await this.props.stateContext.getSocket().getObject(id));
108
- if (obj?.common) {
109
- const min = obj.common.min != null ? Number(obj.common.min) : 0;
110
- const max = obj.common.max != null ? Number(obj.common.max) : 100;
111
- const unit = obj.common.unit || '%';
112
- if (!isNaN(min) && !isNaN(max) && max > min) {
113
- this.setState({ rawMin: min, rawMax: max, unit });
114
- }
115
- // Load common.states for mode selector
116
- const statesObj = obj.common.states;
117
- if (statesObj) {
118
- if (Array.isArray(statesObj)) {
119
- const map = {};
120
- statesObj.forEach((label, i) => {
121
- map[String(i)] = String(label);
122
- });
123
- if (Object.keys(map).length > 0) {
124
- this.setState({ statesMap: map });
125
- }
126
- }
127
- else if (typeof statesObj === 'object') {
128
- const map = statesObj;
129
- if (Object.keys(map).length > 0) {
130
- this.setState({ statesMap: map });
131
- }
132
- }
133
- }
134
- }
135
- }
136
- catch {
137
- // ignore
138
- }
139
- }
140
- /** Convert a raw device value to 0-100 percent */
141
- rawToPercent(raw) {
142
- const { rawMin, rawMax } = this.state;
143
- const range = rawMax - rawMin;
144
- if (range <= 0) {
145
- return 0;
146
- }
147
- return Math.round(((raw - rawMin) / range) * 100);
148
- }
149
- /** Convert a 0-100 percent to a raw device value */
150
- percentToRaw(percent) {
151
- const { rawMin, rawMax } = this.state;
152
- return rawMin + (percent / 100) * (rawMax - rawMin);
153
- }
154
- onLevelChange = (_id, state) => {
155
- if (this.isDragging) {
156
- return;
157
- }
158
- const rawValue = Number(state.val) || 0;
159
- const level = this.rawToPercent(rawValue);
160
- if (level !== this.state.level || rawValue !== this.state.rawValue) {
161
- this.setState({ level, rawValue });
162
- }
163
- };
164
- getSliderType() {
165
- return this.props.settings?.sliderType || 'normal';
166
- }
167
- // --- Mode selector helpers ---
168
- isModeSelectorMode() {
169
- return this.state.statesMap != null && Object.keys(this.state.statesMap).length > 0;
170
- }
171
- getCurrentModeName() {
172
- const { statesMap, rawValue } = this.state;
173
- if (!statesMap) {
174
- return '';
175
- }
176
- return statesMap[String(rawValue)] || statesMap[String(Math.round(rawValue))] || String(rawValue);
177
- }
178
- selectMode(value) {
179
- const numValue = Number(value);
180
- if (this.setId) {
181
- void this.props.stateContext.getSocket().setState(this.setId, numValue);
182
- }
183
- this.setState({
184
- rawValue: numValue,
185
- level: this.rawToPercent(numValue),
186
- modeDialogOpen: false,
187
- });
188
- }
189
- // --- Arc knob pointer interaction ---
190
- pointerToPercent(clientX, clientY) {
191
- const el = this.arcRef.current;
192
- if (!el) {
193
- return this.state.level;
194
- }
195
- // Valve compact: vertical mapping — top = 100%, bottom = 0%
196
- if (this.verticalDragMode) {
197
- const rect = el.getBoundingClientRect();
198
- const y = clientY - rect.top;
199
- const pct = Math.round((1 - y / rect.height) * 100);
200
- return Math.max(0, Math.min(100, pct));
201
- }
202
- // Arc calculation for other types
203
- const rect = el.getBoundingClientRect();
204
- const cx = rect.left + rect.width / 2;
205
- const cy = rect.top + rect.height / 2;
206
- const dx = clientX - cx;
207
- const dy = clientY - cy;
208
- let angle = Math.atan2(dy, dx) * (180 / Math.PI);
209
- if (angle < 0) {
210
- angle += 360;
211
- }
212
- let normalized = angle - 135;
213
- if (normalized < 0) {
214
- normalized += 360;
215
- }
216
- if (normalized > 270) {
217
- return normalized > 315 ? 0 : 100;
218
- }
219
- return Math.round((normalized / 270) * 100);
220
- }
221
- onArcPointerDown = (e) => {
222
- e.preventDefault();
223
- e.target.setPointerCapture(e.pointerId);
224
- this.dragStartPos = { x: e.clientX, y: e.clientY };
225
- this.isDragging = false;
226
- };
227
- onArcPointerMove = (e) => {
228
- if (!this.dragStartPos) {
229
- return;
230
- }
231
- const dx = e.clientX - this.dragStartPos.x;
232
- const dy = e.clientY - this.dragStartPos.y;
233
- if (!this.isDragging && Math.sqrt(dx * dx + dy * dy) > 8) {
234
- this.isDragging = true;
235
- this.setState({ dragging: true });
236
- }
237
- if (this.isDragging) {
238
- const percent = this.pointerToPercent(e.clientX, e.clientY);
239
- this.setState({ level: percent, rawValue: this.percentToRaw(percent) });
240
- }
241
- };
242
- onArcPointerUp = (e) => {
243
- if (!this.dragStartPos) {
244
- return;
245
- }
246
- if (this.isDragging) {
247
- const percent = this.pointerToPercent(e.clientX, e.clientY);
248
- if (this.setId) {
249
- void this.props.stateContext.getSocket().setState(this.setId, this.percentToRaw(percent));
250
- }
251
- }
252
- this.dragStartPos = null;
253
- this.isDragging = false;
254
- this.setState({ dragging: false });
255
- };
256
- // --- Slider handlers for wide modes ---
257
- onSliderDrag = (_e, value) => {
258
- const level = value;
259
- this.setState({ level, rawValue: this.percentToRaw(level), dragging: true });
260
- };
261
- onSliderCommit = (_e, value) => {
262
- const level = value;
263
- if (this.setId) {
264
- void this.props.stateContext.getSocket().setState(this.setId, this.percentToRaw(level));
265
- }
266
- this.setState({ level, rawValue: this.percentToRaw(level), dragging: false });
267
- };
268
- // --- Chart support ---
269
- getHistoryIds() {
270
- const id = this.actualId || this.setId;
271
- if (!id) {
272
- return [];
273
- }
274
- return [{ id, color: this.getAccentColor() || '#1976d2' }];
275
- }
276
- // --- Overrides ---
277
- isTileActive() {
278
- if (this.isModeSelectorMode()) {
279
- return true;
280
- }
281
- return this.state.level > 0;
282
- }
283
- // eslint-disable-next-line class-methods-use-this
284
- hasTileAction() {
285
- return true;
286
- }
287
- onTileClick() {
288
- if (this.isModeSelectorMode()) {
289
- this.setState({ modeDialogOpen: true });
290
- return;
291
- }
292
- // Toggle between 0 and last value or 100
293
- const newLevel = this.state.level > 0 ? 0 : 100;
294
- if (this.setId) {
295
- void this.props.stateContext.getSocket().setState(this.setId, this.percentToRaw(newLevel));
296
- }
297
- this.setState({ level: newLevel, rawValue: this.percentToRaw(newLevel) });
298
- }
299
- renderTypeIcon(sx) {
300
- const baseIcon = this.renderBaseIcon();
301
- if (baseIcon) {
302
- return baseIcon;
303
- }
304
- const sliderType = this.getSliderType();
305
- const isActive = this.isTileActive();
306
- const accent = this.getAccentColor();
307
- const iconSx = sx ||
308
- ((theme) => ({
309
- color: isActive ? accent || theme.palette.primary.main : theme.palette.text.disabled,
310
- transition: 'color 0.25s ease',
311
- }));
312
- switch (sliderType) {
313
- case 'valve':
314
- return React.createElement(ValveIcon, { sx: iconSx });
315
- case 'fan':
316
- return (React.createElement(FanIcon, { sx: theme => ({
317
- ...(typeof iconSx === 'function' ? iconSx(theme) : iconSx),
318
- animation: isActive ? 'wm-spin 2s linear infinite' : 'none',
319
- '@keyframes wm-spin': {
320
- '0%': { transform: 'rotate(0deg)' },
321
- '100%': { transform: 'rotate(360deg)' },
322
- },
323
- }) }));
324
- case 'gauge':
325
- return React.createElement(Speed, { sx: iconSx });
326
- default:
327
- return React.createElement(Tune, { sx: iconSx });
328
- }
329
- }
330
- renderTileIcon() {
331
- return this.renderTypeIcon();
332
- }
333
- renderTileStatus() {
334
- if (this.isModeSelectorMode()) {
335
- const modeName = this.getCurrentModeName();
336
- const accent = this.getAccentColor();
337
- return (React.createElement(Typography, { variant: "caption", sx: theme => ({
338
- fontWeight: 500,
339
- color: accent || theme.palette.primary.main,
340
- transition: 'color 0.25s ease',
341
- }) }, modeName));
342
- }
343
- const { level, rawValue, unit } = this.state;
344
- const isActive = this.isTileActive();
345
- const accent = this.getAccentColor();
346
- const displayValue = unit === '%' ? `${level}%` : `${Math.round(rawValue)} ${unit}`;
347
- return (React.createElement(Typography, { variant: "caption", sx: theme => ({
348
- fontWeight: 500,
349
- color: isActive ? accent || theme.palette.primary.main : theme.palette.text.secondary,
350
- transition: 'color 0.25s ease',
351
- }) }, isActive ? displayValue : I18n.t('wm_Off')));
352
- }
353
- // --- Mode selector rendering ---
354
- renderModeDialog() {
355
- const { statesMap, modeDialogOpen, rawValue } = this.state;
356
- if (!statesMap || !modeDialogOpen) {
357
- return null;
358
- }
359
- const entries = Object.entries(statesMap);
360
- const currentKey = String(Math.round(rawValue));
361
- const accent = this.getAccentColor();
362
- return (React.createElement(Dialog, { open: true, onClose: () => this.setState({ modeDialogOpen: false }), maxWidth: "xs", fullWidth: true },
363
- React.createElement(DialogTitle, null, this.props.settings?.name || this.state.name || '...'),
364
- React.createElement(DialogContent, null,
365
- React.createElement(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 1, pb: 1 } }, entries.map(([value, label]) => {
366
- const selected = currentKey === value;
367
- return (React.createElement(Chip, { key: value, label: label, variant: selected ? 'filled' : 'outlined', color: selected ? 'primary' : 'default', onClick: () => this.selectMode(value), sx: selected && accent
368
- ? {
369
- backgroundColor: accent,
370
- '&:hover': { backgroundColor: accent },
371
- }
372
- : undefined }));
373
- })))));
374
- }
375
- renderModeAction() {
376
- const { statesMap, rawValue } = this.state;
377
- if (!statesMap) {
378
- return React.createElement(Box, null);
379
- }
380
- const entries = Object.entries(statesMap);
381
- const currentKey = String(Math.round(rawValue));
382
- const accent = this.getAccentColor();
383
- const totalLength = entries.reduce((sum, [, label]) => sum + label.length, 0);
384
- // Short labels and few modes: show inline chips
385
- if (entries.length <= 4 && totalLength <= 30) {
386
- return (React.createElement(Box, { sx: { display: 'flex', gap: 0.5, flexWrap: 'wrap' }, onClick: e => e.stopPropagation() }, entries.map(([value, label]) => {
387
- const selected = currentKey === value;
388
- return (React.createElement(Chip, { key: value, label: label, size: "small", variant: selected ? 'filled' : 'outlined', color: selected ? 'primary' : 'default', onClick: () => this.selectMode(value), sx: selected && accent
389
- ? {
390
- backgroundColor: accent,
391
- '&:hover': { backgroundColor: accent },
392
- }
393
- : undefined }));
394
- })));
395
- }
396
- // Too many or too long: show current mode chip → opens dialog
397
- const modeName = this.getCurrentModeName();
398
- return (React.createElement(Chip, { label: modeName, size: "small", color: "primary", sx: accent ? { backgroundColor: accent, '&:hover': { backgroundColor: accent } } : undefined, onClick: e => {
399
- e.stopPropagation();
400
- this.setState({ modeDialogOpen: true });
401
- } }));
402
- }
403
- renderModeCompact() {
404
- const { name } = this.state;
405
- const modeName = this.getCurrentModeName();
406
- const isActive = this.isTileActive();
407
- const accent = this.getAccentColor();
408
- const settingsButton = this.renderSettingsButton();
409
- const indicators = this.renderIndicators(settingsButton);
410
- return (React.createElement(Box, { id: String(this.props.widget.id), className: this.getWidgetClass(), sx: theme => WidgetGeneric.getStyleCompact(theme) },
411
- React.createElement(ButtonBase, { component: "div", onClick: () => this.setState({ modeDialogOpen: true }), sx: theme => ({
412
- display: 'flex',
413
- flexDirection: 'column',
414
- justifyContent: 'space-between',
415
- alignItems: 'stretch',
416
- width: '100%',
417
- aspectRatio: '1',
418
- textAlign: 'left',
419
- overflow: 'hidden',
420
- ...getTileStyles(theme, isActive, accent),
421
- padding: isNeumorphicTheme(theme) ? 'max(12px, 8cqi)' : 'max(16px, 10cqi)',
422
- }) },
423
- indicators,
424
- React.createElement(Box, { sx: {
425
- display: 'flex',
426
- alignItems: 'center',
427
- justifyContent: 'center',
428
- flex: 1,
429
- fontSize: 'max(48px, 32cqi)',
430
- '& .MuiSvgIcon-root': { fontSize: 'inherit !important' },
431
- } }, this.renderTileIcon()),
432
- React.createElement(Box, null,
433
- React.createElement(Typography, { ref: this.nameRef, variant: "body2", sx: theme => ({
434
- fontWeight: 600,
435
- lineHeight: 1.3,
436
- overflow: 'hidden',
437
- whiteSpace: 'nowrap',
438
- fontSize: 'max(0.875rem, 9cqi)',
439
- ...(isNeumorphicTheme(theme)
440
- ? {
441
- textTransform: 'uppercase',
442
- letterSpacing: '0.08em',
443
- fontSize: 'max(0.6rem, 6cqi)',
444
- }
445
- : {}),
446
- }) }, this.props.settings?.name || name || '...'),
447
- React.createElement(Typography, { variant: "caption", sx: theme => ({
448
- fontWeight: 500,
449
- color: accent || theme.palette.primary.main,
450
- transition: 'color 0.25s ease',
451
- }) }, modeName)),
452
- this.renderChart()),
453
- this.renderModeDialog()));
454
- }
455
- // --- Arc knob for wide views ---
456
- renderArcKnob() {
457
- this.verticalDragMode = false;
458
- const { level, rawValue, unit, dragging } = this.state;
459
- const isActive = this.isTileActive();
460
- const accent = this.getAccentColor();
461
- const vb = 100;
462
- const sw = 10;
463
- const r = (vb - sw) / 2;
464
- const circumference = 2 * Math.PI * r;
465
- const arcLength = circumference * 0.75;
466
- const progress = (level / 100) * arcLength;
467
- const displayValue = unit === '%' ? `${level}%` : `${Math.round(rawValue)} ${unit}`;
468
- return (React.createElement(Box, { ref: this.arcRef, onPointerDown: this.onArcPointerDown, onPointerMove: this.onArcPointerMove, onPointerUp: this.onArcPointerUp, onPointerCancel: this.onArcPointerUp, onClick: e => e.stopPropagation(), sx: {
469
- width: 48,
470
- height: 48,
471
- flexShrink: 0,
472
- touchAction: 'none',
473
- userSelect: 'none',
474
- cursor: 'pointer',
475
- display: 'flex',
476
- alignItems: 'center',
477
- justifyContent: 'center',
478
- position: 'relative',
479
- } },
480
- React.createElement("svg", { viewBox: `0 0 ${vb} ${vb}`, style: { width: '100%', height: '100%', transform: 'rotate(135deg)' } },
481
- 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 }),
482
- React.createElement("circle", { cx: vb / 2, cy: vb / 2, r: r, fill: "none", stroke: isActive ? accent || 'var(--mui-palette-primary-main, #1976d2)' : 'transparent', strokeWidth: sw, strokeDasharray: `${progress} ${circumference}`, strokeLinecap: "round", style: dragging ? undefined : { transition: 'stroke-dasharray 0.3s ease' } })),
483
- React.createElement(Typography, { sx: {
484
- position: 'absolute',
485
- fontSize: '0.6rem',
486
- fontWeight: 700,
487
- lineHeight: 1,
488
- color: isActive ? accent || 'primary.main' : 'text.secondary',
489
- } }, isActive ? displayValue : I18n.t('wm_Off'))));
490
- }
491
- renderTileAction() {
492
- if (this.isModeSelectorMode()) {
493
- return (React.createElement(React.Fragment, null,
494
- this.renderModeAction(),
495
- this.renderModeDialog()));
496
- }
497
- const { level } = this.state;
498
- const accent = this.getAccentColor();
499
- if ((this.props.settings?.wideSliderStyle || 'horizontal') === 'round') {
500
- return this.renderArcKnob();
501
- }
502
- return (React.createElement(MuiSlider, { value: level, min: 0, max: 100, size: "small", onClick: e => e.stopPropagation(), onChange: this.onSliderDrag, onChangeCommitted: this.onSliderCommit, sx: theme => ({
503
- width: 80,
504
- color: accent || theme.palette.primary.main,
505
- '& .MuiSlider-thumb': { width: 14, height: 14 },
506
- }) }));
507
- }
508
- // --- Valve compact: vertical fill bar ---
509
- renderValveCompact() {
510
- this.verticalDragMode = true;
511
- const { name, level, rawValue, unit, dragging } = this.state;
512
- const isActive = this.isTileActive();
513
- const accent = this.getAccentColor();
514
- const settingsButton = this.renderSettingsButton();
515
- const indicators = this.renderIndicators(settingsButton);
516
- const displayValue = unit === '%' ? `${level}%` : `${Math.round(rawValue)} ${unit}`;
517
- const accentOrDefault = accent || '#1976d2';
518
- return (React.createElement(Box, { id: String(this.props.widget.id), className: this.getWidgetClass(), sx: theme => WidgetGeneric.getStyleCompact(theme) },
519
- React.createElement(Box, { ref: this.arcRef, onPointerDown: this.onArcPointerDown, onPointerMove: this.onArcPointerMove, onPointerUp: this.onArcPointerUp, onPointerCancel: this.onArcPointerUp, sx: theme => ({
520
- display: 'flex',
521
- flexDirection: 'column',
522
- justifyContent: 'space-between',
523
- alignItems: 'stretch',
524
- width: '100%',
525
- aspectRatio: '1',
526
- textAlign: 'left',
527
- overflow: 'hidden',
528
- cursor: 'pointer',
529
- touchAction: 'none',
530
- userSelect: 'none',
531
- position: 'relative',
532
- ...getTileStyles(theme, isActive, accent),
533
- padding: isNeumorphicTheme(theme) ? 'max(12px, 8cqi)' : 'max(16px, 10cqi)',
534
- }) },
535
- React.createElement(Box, { sx: {
536
- position: 'absolute',
537
- bottom: 0,
538
- left: 0,
539
- right: 0,
540
- height: `${level}%`,
541
- backgroundColor: accentOrDefault,
542
- opacity: 0.15,
543
- borderRadius: '0 0 14px 14px',
544
- transition: dragging ? 'none' : 'height 0.3s ease',
545
- } }),
546
- indicators,
547
- React.createElement(Box, { sx: {
548
- display: 'flex',
549
- flexDirection: 'column',
550
- alignItems: 'center',
551
- justifyContent: 'center',
552
- flex: 1,
553
- position: 'relative',
554
- zIndex: 1,
555
- fontSize: 'max(48px, 32cqi)',
556
- '& .MuiSvgIcon-root': { fontSize: 'inherit !important' },
557
- } },
558
- this.renderTypeIcon(),
559
- React.createElement(Typography, { variant: "body2", sx: theme => ({
560
- fontWeight: 700,
561
- fontSize: 'max(1.2rem, 14cqi)',
562
- mt: 0.5,
563
- color: isActive ? accentOrDefault : theme.palette.text.secondary,
564
- transition: 'color 0.25s ease',
565
- }) }, isActive ? displayValue : I18n.t('wm_Off'))),
566
- React.createElement(Box, { sx: { position: 'relative', zIndex: 1 } },
567
- React.createElement(Typography, { ref: this.nameRef, variant: "body2", sx: theme => ({
568
- fontWeight: 600,
569
- lineHeight: 1.3,
570
- overflow: 'hidden',
571
- whiteSpace: 'nowrap',
572
- fontSize: 'max(0.875rem, 9cqi)',
573
- ...(isNeumorphicTheme(theme)
574
- ? {
575
- textTransform: 'uppercase',
576
- letterSpacing: '0.08em',
577
- fontSize: 'max(0.6rem, 6cqi)',
578
- }
579
- : {}),
580
- }) }, this.props.settings?.name || name || '...')),
581
- this.renderChart())));
582
- }
583
- // --- Arc compact: used for normal, fan, gauge ---
584
- renderArcCompact() {
585
- this.verticalDragMode = false;
586
- const { name, level, dragging } = this.state;
587
- const isActive = this.isTileActive();
588
- const accent = this.getAccentColor();
589
- const settingsButton = this.renderSettingsButton();
590
- const indicators = this.renderIndicators(settingsButton);
591
- const vb = 100;
592
- const sw = 8;
593
- const r = (vb - sw) / 2;
594
- const circumference = 2 * Math.PI * r;
595
- const arcLength = circumference * 0.75; // 270°
596
- const progress = (level / 100) * arcLength;
597
- return (React.createElement(Box, { id: String(this.props.widget.id), className: this.getWidgetClass(), sx: theme => WidgetGeneric.getStyleCompact(theme) },
598
- React.createElement(Box, { ref: this.arcRef, onPointerDown: this.onArcPointerDown, onPointerMove: this.onArcPointerMove, onPointerUp: this.onArcPointerUp, onPointerCancel: this.onArcPointerUp, sx: theme => ({
599
- display: 'flex',
600
- flexDirection: 'column',
601
- justifyContent: 'space-between',
602
- alignItems: 'stretch',
603
- width: '100%',
604
- aspectRatio: '1',
605
- textAlign: 'left',
606
- overflow: 'hidden',
607
- cursor: 'pointer',
608
- touchAction: 'none',
609
- userSelect: 'none',
610
- ...getTileStyles(theme, isActive, accent),
611
- ...(isNeumorphicTheme(theme) ? { padding: 'max(12px, 8cqi)' } : {}),
612
- }) },
613
- indicators,
614
- React.createElement(Box, { sx: {
615
- display: 'flex',
616
- alignItems: 'center',
617
- justifyContent: 'center',
618
- position: 'relative',
619
- flex: 1,
620
- } },
621
- React.createElement("svg", { viewBox: `0 0 ${vb} ${vb}`, style: { width: '60%', height: '60%', transform: 'rotate(135deg)' } },
622
- 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 }),
623
- React.createElement("circle", { cx: vb / 2, cy: vb / 2, r: r, fill: "none", stroke: isActive ? accent || 'var(--mui-palette-primary-main, #1976d2)' : 'transparent', strokeWidth: sw, strokeDasharray: `${progress} ${circumference}`, strokeLinecap: "round", style: dragging ? undefined : { transition: 'stroke-dasharray 0.3s ease' } })),
624
- React.createElement(Box, { sx: {
625
- position: 'absolute',
626
- display: 'flex',
627
- alignItems: 'center',
628
- justifyContent: 'center',
629
- } }, this.renderTileIcon())),
630
- React.createElement(Box, null,
631
- React.createElement(Typography, { ref: this.nameRef, variant: "body2", sx: theme => ({
632
- fontWeight: 600,
633
- lineHeight: 1.3,
634
- overflow: 'hidden',
635
- whiteSpace: 'nowrap',
636
- ...(isNeumorphicTheme(theme)
637
- ? {
638
- textTransform: 'uppercase',
639
- letterSpacing: '0.08em',
640
- fontSize: 'max(0.6rem, 6cqi)',
641
- }
642
- : {}),
643
- }) }, this.props.settings?.name || name || '...'),
644
- this.renderTileStatus()),
645
- this.renderChart())));
646
- }
647
- renderCompact() {
648
- if (this.isModeSelectorMode()) {
649
- return this.renderModeCompact();
650
- }
651
- if (this.getSliderType() === 'valve') {
652
- return this.renderValveCompact();
653
- }
654
- return this.renderArcCompact();
655
- }
656
- }
657
- export default WidgetSlider;
658
- //# sourceMappingURL=Slider.js.map