@adcops/autocore-react 3.0.6 → 3.0.10

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.
@@ -2,428 +2,284 @@
2
2
  * Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
3
3
  * Created Date: 2024-03-12 10:14:48
4
4
  * -----
5
- * Last Modified: 2024-03-12 20:40:14
5
+ * Last Modified: 2024-04-16 09:16:59
6
6
  * -----
7
7
  *
8
8
  */
9
9
 
10
- import { Component } from 'react';
10
+ import React, { useState, useEffect, useContext } from 'react';
11
11
  import { SelectButton, SelectButtonProps } from 'primereact/selectbutton';
12
12
  import {SelectItemOptionsType} from "primereact/selectitem";
13
13
 
14
- import { EventEmitterContext, EventEmitterContextType } from '../core/EventEmitterContext';
14
+ import { EventEmitterContext} from '../core/EventEmitterContext';
15
15
  import {IndicatorColor} from "../core/IndicatorColor";
16
16
  export {IndicatorColor}
17
17
  import { ActionMode } from '../core/ActionMode';
18
18
  export {ActionMode};
19
19
 
20
- import { IndicatorButtonState } from '../core/IndicatorButtonState';
20
+ import clsx from 'clsx';
21
21
 
22
22
 
23
23
 
24
24
  export interface ToggleGroupProps extends SelectButtonProps {
25
-
26
- /**
27
- * Label of the group/row. Can be any element.
28
- *
29
- * ## Examples
30
- * ```
31
- * <ToggleGroup label="Simple Text" />
32
- * <ToggleGroup label={<span><i className="pi pi-check"></i> Icon and Text</span>} />
33
- * <ToggleGroup label={<YourCustomIconComponent />} />
34
- * ```
35
- */
36
- label? : React.ReactNode;
37
-
38
-
39
- /**
40
- * Topic name to monitor for state indication.
41
- * If `value` field is not undefined, then that value is used instead.
42
- */
25
+ label?: React.ReactNode;
43
26
  topic?: string;
44
-
45
- /**
46
- * Color for the button when the state is TRUE.
47
- */
48
27
  onColor?: IndicatorColor | IndicatorColor[];
49
-
50
- /**
51
- * Color for the button when the state is FALSE.
52
- */
53
28
  offColor?: IndicatorColor;
54
-
55
-
56
- /**
57
- * Name of the command to invoke on button events.
58
- * If command is "*", then the commandTopic will be dispatched
59
- * internally.
60
- */
61
29
  command?: string;
62
-
63
- /**
64
- * Optional topic parameter to send along with the command.
65
- * If set, will automatically be included with commandArgs as
66
- * the value of field 'topic.'
67
- */
68
- commandTopic? : string;
69
-
70
- /**
71
- * Optional arguments sent with the command.
72
- */
30
+ commandTopic?: string;
73
31
  commandArgs?: any;
74
-
75
- /**
76
- * Topic to disable button interaction.
77
- */
78
32
  disableTopic?: string;
79
-
80
- /**
81
- * Topic to control the visibility of the button.
82
- */
83
33
  invisibleTopic?: string;
84
-
85
- /**
86
- * Mode of input for the button (e.g., TAP, TOGGLE).
87
- */
88
34
  actionMode?: ActionMode;
89
-
90
- /**
91
- * Inverts the signal values for TAP, PRESSED, and RELEASED modes.
92
- */
93
35
  invert?: boolean;
94
36
  }
95
37
 
96
-
97
- /**
98
- *
99
- * @param s string | undefined[]
100
- * @returns
101
- */
102
- // function generateSelectButtonOptions(s? : SelectItemOptionsType | undefined) : SelectItemOptionsType | undefined {
103
- // if (s !== undefined && s !== null) {
104
- // let ret : SelectItemOptionsType = [];
105
- // for (let i=0;i<s.length;++i) {
106
- // ret.push({label:s[i]});
107
- // }
108
-
109
- // return ret;
110
- // }
111
- // else {
112
- // return undefined;
113
- // }
114
- // }
115
-
116
-
117
- /**
118
- *
119
- * @param currentValue
120
- * @param options
121
- * @returns
122
- */
123
- function matchCurrentValue(currentValue : any, options : SelectItemOptionsType | undefined) : any {
124
-
125
- if (options === undefined || options === null || options.length === 0)
126
- return undefined;
127
-
128
- let t = typeof(currentValue);
129
- if (t == "boolean" ) {
130
- let b = currentValue as boolean;
131
- if (b) {
132
- if (options.length > 1 )
133
- return options[1];
134
- else
135
- return options[0];
136
- }
137
- else {
138
- return options[0];
139
- }
140
- }
141
- else if (t == "number") {
142
- let n = currentValue as number;
143
- if (n !== undefined && n < options.length ) {
144
- return options[n];
145
- }
146
- }
147
- else if (t == "string") {
148
- // The SelectButton should match to this value automatically, if it's in the
149
- // options array. No reason to search twice.
150
- return currentValue;
151
- }
152
-
153
-
154
- return undefined;
155
- }
156
-
157
-
158
-
159
- /**
160
- *
161
- * @param currentValue
162
- * @param options
163
- * @returns
164
- */
165
-
166
- function selectOnColor(
167
- currentValue: any,
168
- options: SelectItemOptionsType | undefined,
169
- onColorProp: IndicatorColor | IndicatorColor[] | undefined
170
- ): IndicatorColor {
171
-
172
- if (!options || options.length === 0)
173
- return IndicatorColor.IndicatorInvalid;
174
-
175
- let colorArray =
176
- Array.isArray(onColorProp) ? onColorProp :
177
- onColorProp !== undefined ? [onColorProp] : [IndicatorColor.IndicatorInvalid];
178
-
179
- let t = typeof(currentValue);
180
- if (t === "boolean") {
181
- return currentValue ? colorArray[0] : colorArray.length > 1 ? colorArray[1] : colorArray[0];
182
- }
183
- else if (t === "number" && options.length > currentValue) {
184
- if (colorArray.length > currentValue) {
185
- let index = currentValue as number;
186
- return colorArray[index];
187
- }
188
- else {
189
- return colorArray[0];
190
- }
191
- }
192
- else if (t === "string") {
193
- let index = options.indexOf(currentValue);
194
- if (index !== -1 && index < colorArray.length)
195
- return colorArray[index];
196
- else
197
- return colorArray[0];
198
- }
199
-
200
- if (onColorProp !== undefined && onColorProp !== null) {
201
- return Array.isArray(onColorProp) ? onColorProp[0] : onColorProp as IndicatorColor;
202
- }
203
- else {
204
- return IndicatorColor.IndicatorInvalid;
205
- }
206
-
207
- }
208
-
209
-
210
- export class ToggleGroup extends Component<ToggleGroupProps, IndicatorButtonState> {
211
-
212
- static contextType = EventEmitterContext;
213
-
214
- constructor(props: ToggleGroupProps) {
215
- super(props);
216
- this.state = {
217
- currentValue: undefined,
218
- isDisabled: false,
219
- isInvisible: false,
220
- isPressed: false
38
+ export const ToggleGroup: React.FC<ToggleGroupProps> = ({
39
+ label,
40
+ topic,
41
+ onColor,
42
+ offColor,
43
+ command,
44
+ commandTopic,
45
+ commandArgs,
46
+ disableTopic,
47
+ invisibleTopic,
48
+ actionMode,
49
+ invert,
50
+ ...restProps
51
+ }) => {
52
+
53
+ const [uniqueId] = useState(() => `toggleGroup-${Math.random().toString(36).substr(2, 9)}`);
54
+
55
+ const [currentValue, setCurrentValue] = useState<any>(undefined);
56
+ const [isDisabled, setIsDisabled] = useState<boolean>(false);
57
+ const [isInvisible, setIsInvisible] = useState<boolean>(false);
58
+ const [isPressed, setIsPressed] = useState<boolean>(false);
59
+ const context = useContext(EventEmitterContext);
60
+
61
+ useEffect(() => {
62
+ const setupSubscriptions = () => {
63
+ if (topic) {
64
+ context.subscribe(topic, handleTopicUpdate);
65
+ }
66
+ if (disableTopic) {
67
+ context.subscribe(disableTopic, handleDisableTopicUpdate);
68
+ }
69
+ if (invisibleTopic) {
70
+ context.subscribe(invisibleTopic, handleInvisibleTopicUpdate);
71
+ }
221
72
  };
222
- }
223
73
 
224
- componentDidMount() {
225
- this.setupSubscriptions();
226
- }
74
+ setupSubscriptions();
227
75
 
228
- componentDidUpdate(prevProps: ToggleGroupProps) {
229
- prevProps;
230
- // Logic to handle updates in props, if necessary
231
- }
232
-
233
- componentWillUnmount() {
234
- // Unsubscribe logic if needed
235
- }
236
-
237
- /**
238
- * Sets up subscriptions based on provided topics.
239
- */
240
- private setupSubscriptions() {
241
- const { topic, disableTopic, invisibleTopic } = this.props;
242
- const { subscribe } = this.context as EventEmitterContextType;
243
-
244
- if (topic) {
245
- // Subscribe to the main topic
246
- subscribe(topic, this.handleTopicUpdate);
247
- }
248
-
249
- if (disableTopic) {
250
- // Subscribe to the disable topic
251
- subscribe(disableTopic, this.handleDisableTopicUpdate);
252
- }
253
-
254
- if (invisibleTopic) {
255
- // Subscribe to the invisible topic
256
- subscribe(invisibleTopic, this.handleInvisibleTopicUpdate);
257
- }
258
- }
76
+ return () => {
77
+ // Unsubscribe logic here
78
+ };
79
+ }, [topic, disableTopic, invisibleTopic]);
259
80
 
260
- /**
261
- * Handles updates for the main topic.
262
- */
263
- private handleTopicUpdate = (value: boolean) => {
264
- this.setState({ currentValue: value });
81
+ const handleTopicUpdate = (value: boolean) => {
82
+ setCurrentValue(value);
265
83
  };
266
84
 
267
- /**
268
- * Handles updates for the disable topic.
269
- */
270
- private handleDisableTopicUpdate = (value: boolean) => {
271
- this.setState({ isDisabled: value });
85
+ const handleDisableTopicUpdate = (value: boolean) => {
86
+ setIsDisabled(value);
272
87
  };
273
88
 
274
- /**
275
- * Handles updates for the invisible topic.
276
- */
277
- private handleInvisibleTopicUpdate = (value: boolean) => {
278
- this.setState({ isInvisible: value });
279
- };
280
-
89
+ const handleInvisibleTopicUpdate = (value: boolean) => {
90
+ setIsInvisible(value);
91
+ };
281
92
 
282
- /**
283
- * Handle the button being pressed down. Used for TAP and PRESSED action modes.
284
- */
285
- protected handleOnPressed() {
286
- const { isPressed } = this.state;
287
- const {actionMode} = this.props;
288
-
93
+ const handleOnPressed = () => {
289
94
  if (!isPressed) {
290
- this.setState({isPressed: true});
291
-
95
+ setIsPressed(true);
292
96
  if (actionMode === ActionMode.Tap || actionMode === ActionMode.Pressed) {
293
- this.dispatchCommand(true);
97
+ dispatchCommand(true);
294
98
  }
295
99
  }
296
- }
100
+ };
297
101
 
298
- /**
299
- * Handle the button being released. Used for TAP and RELEASED action modes.
300
- */
301
- protected handleOnReleased() {
302
- const { isPressed } = this.state;
303
- const {actionMode} = this.props;
304
-
102
+ const handleOnReleased = () => {
305
103
  if (isPressed) {
306
- this.setState({isPressed: false});
307
-
308
- if (actionMode === ActionMode.Tap ) {
309
- this.dispatchCommand(false);
310
- }
311
- else if (actionMode === ActionMode.Released) {
312
- this.dispatchCommand(true);
104
+ setIsPressed(false);
105
+ if (actionMode === ActionMode.Tap) {
106
+ dispatchCommand(false);
107
+ } else if (actionMode === ActionMode.Released) {
108
+ dispatchCommand(true);
313
109
  }
314
110
  }
315
- }
316
-
317
-
318
- /**
319
- * Dispatch a value to any listeners.
320
- * @param value The value to dispatch as part of the payload.
321
- */
322
- protected dispatchCommand(value : any) {
323
-
324
- const {command, commandTopic, commandArgs} = this.props;
325
- const { dispatch } = this.context as EventEmitterContextType;
111
+ };
326
112
 
327
- if (command !== undefined && command !== null && command.length > 0 )
328
- {
113
+ const dispatchCommand = (value: any) => {
114
+ if (command && command.length > 0) {
329
115
  const payload = {
330
116
  topic: commandTopic,
331
117
  value: value,
332
- ...commandArgs
118
+ ...commandArgs
333
119
  };
334
120
 
335
- dispatch({
121
+ context.dispatch({
336
122
  topic: command,
337
123
  payload: payload
338
124
  });
339
-
340
125
  }
126
+ };
341
127
 
128
+
129
+ let displayValue = currentValue;
130
+ if (restProps.value !== undefined) {
131
+ displayValue = restProps.value;
342
132
  }
343
133
 
344
134
 
135
+ /**
136
+ *
137
+ * @param currentValue
138
+ * @param options
139
+ * @returns
140
+ */
345
141
 
142
+ const selectOnColor = (
143
+ currentValue: any,
144
+ options: SelectItemOptionsType | undefined,
145
+ onColorProp: IndicatorColor | IndicatorColor[] | undefined
146
+ ): IndicatorColor => {
346
147
 
347
- render() {
348
- // const { currentValue, isDisabled, isInvisible } = this.state;
349
- // const { className, severity, label, raised,
350
- // onColor, offColor, options, topic, command,
351
- // commandArgs, disableTopic, invisibleTopic, inputMode, invert,
352
- // onIcon, offIcon, icon,
353
- // ...restProps
354
- // } = this.props;
148
+ if (!options || options.length === 0)
149
+ return IndicatorColor.IndicatorInvalid;
355
150
 
151
+ let colorArray =
152
+ Array.isArray(onColorProp) ? onColorProp :
153
+ onColorProp !== undefined ? [onColorProp] : [IndicatorColor.IndicatorInvalid];
356
154
 
357
- const { currentValue, isDisabled, isInvisible} = this.state;
358
- const { label, value, disabled, className,
359
- onColor, offColor, options,
360
- ...restProps
361
- } = this.props;
155
+ let t = typeof (currentValue);
156
+ if (t === "boolean") {
157
+ return currentValue ? colorArray[0] : colorArray.length > 1 ? colorArray[1] : colorArray[0];
158
+ }
159
+ else if (t === "number" && options.length > currentValue) {
160
+ if (colorArray.length > currentValue) {
161
+ let index = currentValue as number;
162
+ return colorArray[index];
163
+ }
164
+ else {
165
+ return colorArray[0];
166
+ }
167
+ }
168
+ else if (t === "string") {
169
+ let index = options.indexOf(currentValue);
170
+ if (index !== -1 && index < colorArray.length)
171
+ return colorArray[index];
172
+ else
173
+ return colorArray[0];
174
+ }
362
175
 
176
+ if (onColorProp !== undefined && onColorProp !== null) {
177
+ return Array.isArray(onColorProp) ? onColorProp[0] : onColorProp as IndicatorColor;
178
+ }
179
+ else {
180
+ return IndicatorColor.IndicatorInvalid;
181
+ }
363
182
 
364
- // let btnIcon = currentValue ? onIcon : offIcon;
365
- // if (btnIcon === undefined || btnIcon === null || btnIcon.length === 0)
366
- // btnIcon = icon;
183
+ }
367
184
 
368
185
 
369
- //
370
- // Load the value from the proper source.
371
- // If the `value` property is undefined, that takes precedence.
372
- //
373
- let displayValue = currentValue;
374
- if (value !== undefined) {
375
- displayValue = value;
186
+ /**
187
+ *
188
+ * @param currentValue
189
+ * @param options
190
+ * @returns
191
+ */
192
+ const matchCurrentValue = (currentValue: any, options: SelectItemOptionsType | undefined): any => {
193
+
194
+ if (options === undefined || options === null || options.length === 0)
195
+ return undefined;
196
+
197
+ let t = typeof (currentValue);
198
+ if (t == "boolean") {
199
+ let b = currentValue as boolean;
200
+ if (b) {
201
+ if (options.length > 1)
202
+ return options[1];
203
+ else
204
+ return options[0];
205
+ }
206
+ else {
207
+ return options[0];
208
+ }
376
209
  }
377
-
378
- let color = selectOnColor(displayValue, options, onColor); // displayValue ? onColor : offColor;
379
-
380
- // Handle special cases like undefined state or specific input modes
381
- if (displayValue === undefined) {
382
- color = IndicatorColor.IndicatorInvalid;
210
+ else if (t == "number") {
211
+ let n = currentValue as number;
212
+ if (n !== undefined && n < options.length) {
213
+ return options[n];
214
+ }
215
+ }
216
+ else if (t == "string") {
217
+ // The SelectButton should match to this value automatically, if it's in the
218
+ // options array. No reason to search twice.
219
+ return currentValue;
383
220
  }
384
221
 
385
- const isMultiple = options !== undefined && options !== null && options.length > 2;
386
-
387
-
388
- return (
389
- <div className="flex">
390
-
391
- <style>{`
392
- ${offColor !== undefined ? `
393
- .togglegroup-selectbutton-container .p-selectbutton .p-button {
394
- background-color: ${offColor};
395
- }
396
- ` : ''}
397
- .togglegroup-selectbutton-container .p-selectbutton .p-button.p-highlight {
398
- background-color: ${color} !important;
399
- border-color: ${color} !important;
400
- }
401
- .togglegroup-selectbutton-container .p-selectbutton .p-highlight {
402
- background-color: ${color} !important;
403
- border-color: ${color} !important;
222
+
223
+ return undefined;
224
+ }
225
+
226
+
227
+ let color = selectOnColor(displayValue, restProps.options, onColor);
228
+
229
+ if (displayValue === undefined) {
230
+ color = IndicatorColor.IndicatorInvalid;
231
+ }
232
+
233
+ const isMultiple = restProps.options !== undefined
234
+ && restProps.options !== null
235
+ && restProps.options.length !== undefined
236
+ && restProps.options.length > 2
237
+ ;
238
+
239
+
240
+ const toggleGroupName = `${uniqueId}-togglegroup-selectbutton-container`;
241
+
242
+ return (
243
+ <div className="flex">
244
+ {
245
+ <style>{`
246
+ ${offColor !== undefined ? `
247
+ .${toggleGroupName} .p-selectbutton .p-button {
248
+ background-color: ${offColor};
404
249
  }
405
- `}
250
+ ` : ''}
251
+ .${toggleGroupName} .p-selectbutton .p-button.p-highlight {
252
+ background-color: ${color} !important;
253
+ border-color: ${color} !important;
254
+ }
255
+ `}
406
256
  </style>
407
- <div className='p-inputgroup togglegroup-selectbutton-container'>
408
- <span className="p-inputgroup-addon" style={{flexGrow: 1}}>
257
+ }
258
+
259
+ <div className={toggleGroupName}>
260
+
261
+ <div className="p-inputgroup">
262
+
263
+ <span className="p-inputgroup-addon" style={{ flexGrow: 1 }}>
409
264
  {label}
410
- </span>
265
+ </span>
411
266
  <SelectButton {...restProps}
412
- options={options}
413
- disabled={isDisabled || disabled}
267
+ options={restProps.options}
268
+ disabled={isDisabled || restProps.disabled}
414
269
  multiple={isMultiple}
415
- className={`${className || ''} ${displayValue === undefined ? 'p-invalid' : ''}`.trim()}
416
- {...(isInvisible && { style: { display: 'none' }})}
417
- value={matchCurrentValue(displayValue, options)}
418
- allowEmpty={false}
419
- onMouseDown={() => this.handleOnPressed() }
420
- onTouchStart={() => this.handleOnPressed() }
421
- onMouseUp={() => this.handleOnReleased() }
422
- onTouchEnd={() => this.handleOnReleased() }
270
+ className={clsx(uniqueId, restProps.className, { 'p-invalid': restProps.value === undefined })}
271
+ style={isInvisible ? { display: 'none' } : {}}
272
+ value={matchCurrentValue(displayValue, restProps.options)}
273
+ allowEmpty={false}
274
+ onMouseDown={handleOnPressed}
275
+ onTouchStart={handleOnPressed}
276
+ onMouseUp={handleOnReleased}
277
+ onTouchEnd={handleOnReleased}
423
278
  />
424
- </div>
279
+ </div>
425
280
  </div>
426
- );
427
- }
281
+ </div>
282
+ );
283
+ };
428
284
 
429
- }
285
+ export default ToggleGroup;
@@ -0,0 +1,32 @@
1
+ /*
2
+ * Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
3
+ * Created Date: 2024-03-22 06:26:45
4
+ * -----
5
+ * Last Modified: 2024-03-22 07:07:50
6
+ * -----
7
+ *
8
+ */
9
+
10
+
11
+
12
+ .value-indicator-container {
13
+
14
+ display: flex;
15
+ flex-direction: column;
16
+ background-color: var(--surface-ground);
17
+ border-color: var(--surface-border);
18
+ border-radius: var(--border-radius);
19
+ border-width: 1px;
20
+ border-style: solid;
21
+ justify-content: center;
22
+ align-items: center;
23
+ padding: 2mm;
24
+ flex-grow: 1; /* Allow the item to grow to fill available space */
25
+ flex-shrink: 0; /* Allow the item to shrink if necessary */
26
+ flex-basis: 0; /* Start with 0 width and then grow as needed, equal distribution */
27
+ min-width: 0; /* Prevents flex items from overflowing their container */
28
+ }
29
+
30
+ .value-indicator-label {
31
+ padding-bottom: 1mm;
32
+ }