import {Component_A} from './basic/as-component.js';
import {Slider} from './as-slider.js';
import {ErrorCode} from '../exception/exceptionDesc.js';
/**
* @typedef TComponents.VarSliderProps
* @prop {object} [options] General options for the slider behavior.
* Items in this object include:
* - **responsive** (boolean, default: false): Whether the slider width should adapt to the container width.
* @prop {string} [tips] Tooltip text for the component.
* @prop {Function} [onCreated] Function to be called when the component is created.
* @prop {Function} [onMounted] Function to be called when the component is mounted.
* @prop {Function} [onPointerRelease] Callback function that is called when the pointer is released after dragging the slider.
* @prop {Function} [onPointerDown] Callback function that is called while the pointer is dragging the slider.
* @prop {string} [position] CSS position property.
* @prop {number} [width] Width of the component.
* @prop {number} [height] Height of the component.
* @prop {number} [top] Top position of the component.
* @prop {number} [left] Left position of the component.
* @prop {number} [borderRadius] Border radius of the component.
* @prop {number} [rotation] Rotation angle of the component.
* @prop {number} [zIndex] Z-index of the component.
* @prop {string} [color] Font color of the description label.
* @prop {object} [font] Font configuration for the description label.
* This object controls text appearance:
* - **fontSize** (number): Font size in pixels.
* - **fontFamily** (string): Font family name.
* - **style** (object): Font style configuration, containing `fontStyle`, `fontWeight`, `textDecoration`.
* @prop {string} [rangeValueColor] Font color of the min/max range values.
* @prop {object} [rangeValueFont] Font configuration for the min/max range values.
* This object controls range text appearance:
* - **fontSize** (number): Font size in pixels.
* - **fontFamily** (string): Font family name.
* - **style** (object): Font style configuration, containing `fontStyle`, `fontWeight`, `textDecoration`.
* @prop {string} [backgroundColor] Background color of the slider container.
* @prop {string} [border] CSS border style of the slider container.
* @prop {boolean} [displayLabel] Whether to display the description label.
* @prop {string} [descrLabel] Text content of the description label.
* @prop {boolean} [displayValue] Whether to display the current value label.
* @prop {number} [value] Current value of the slider.
* @prop {number} [min] Minimum value of the slider range.
* @prop {number} [max] Maximum value of the slider range.
* @prop {boolean} [enabled] Whether the slider is enabled and interactive.
* @prop {string} [activeColor] Color of the active (filled) part of the slider track.
* @prop {string} [inactiveColor] Color of the inactive part of the slider track.
* @prop {boolean} [displayTicks] Whether to display tick marks along the track.
* @prop {number} [tickStep] Step between tick marks and value increments.
* @prop {object} [inputVar] Input variable binding configuration used in `VarSlider`.
* This object configures the bound input variable:
* - **type** (string): Binding variable type. Default is `'group'`.
* - **func** (string): Binding mode. Default is `'custom'`.
* - **value** (number|string): Initial value or variable path used for binding.
* - **isHidden** (boolean, default: false): Whether this binding is hidden in variable selectors.
* @prop {(string|number)} [text] Value that is parsed and written into the slider `value` in `VarSlider`.
* @prop {string} [defaultState] Initial state of the component.
* @prop {string} [dataStruct] Custom data structure metadata for integration with other systems.
* @memberof TComponents
*/
/**
* @ignore
*/
const logModule = 'as-slider-var';
/**
* @description Slider element. Additional callbacks can be added with the {@link TComponents.Slider#onChange|onChange} method.
* This class focuses on the specific properties of the SliderVar component.
* Since it inherits from Accessor_A, all basic properties (e.g., height, width) are available but documented in the Accessor_A part.
* @class TComponents.VarSlider
* @extends TComponents.Slider
* @memberof TComponents
* @param {HTMLElement} parent - HTML element that is going to be the parent of the component
* @param {TComponents.VarSliderProps} props
* @example
* const slider = new TComponents.VarSlider(document.body,{
* position: 'absolute',
* zIndex: 1000,
* });
*
* // Render the component.
* slider.render();
*/
export class VarSlider extends Slider {
constructor(parent, props = {}) {
super(parent, props);
/**
* @instance
* @private
* @type {TComponents.VarSliderProps}
*/
this._props;
/**
* If bound to web data, `this._bindData` will have the format: { type: 'webdata', key: 'xxx' }.
* If bound to group signal data, `this._bindData` will have the format: { type: 'groupsignal', key: 'xxxx' }.
* If bound to rapid data, `this._bindData` will have the format: { type: 'rapiddata', dataType: 'xxx', module: 'xxx', name: 'xxx', task: 'xxx' }.
*/
this._bindData;
}
/**
* @description Returns the default values of class properties (excluding parent properties).
* @member TComponents.VarSlider#defaultProps
* @method
* @protected
* @returns {TComponents.VarSliderProps}
*/
defaultProps() {
const parentProps = super.defaultProps();
return Object.assign({}, parentProps, {
// Bind variable properties
inputVar: {
type: 'group', // 'any' | 'string' | 'num' | 'bool' | 'group'
func: 'custom', // 'custom' | 'sync'
value: 30,
isHidden: false,
},
text: '',
options: {
responsive: false,
},
dataStruct: '',
});
}
/**
* @description there are something need to do after render once
* @member TComponents.VarSlider#afterRenderOnce
* @method
* @protected
* @returns {void}
*/
afterRenderOnce() {
if (this._props.inputVar.func == 'sync') {
this._bindData = Component_A.getBindData(this._props.inputVar.value, this);
}
}
/**
* @description Renders the slider component.
* @member TComponents.VarSlider#onRender
* @method
* @throws {Error} Throws an error if rendering fails.
* @returns {void}
*/
onRender() {
try {
this.removeAllEventListeners();
super.onRender();
this.text = this._props.text;
Component_A.resolveBindingExpression(this._props.text, this);
} catch (e) {
// Runtime errors: write specific content to the log, throw error code
Logger.e(
logModule,
ErrorCode.FailedToRunOnRender,
`Error happens on onRender of slider component ${this.compId}.`,
e.toString(),
);
throw new Error(ErrorCode.FailedToRunOnRender, {cause: e});
}
}
/**
* @description Pointer up/leave event handler.
* @member TComponents.VarSlider~_onPointerRelease
* @method
* @private
* @async
* @param {number} value - The current value of the slider when pointer is released
* @returns {Promise<void>}
*/
async _onPointerRelease(value) {
if (this.enabled) {
let tempVal = value;
const oldVal = this._props.text;
try {
await this.syncInputData(tempVal);
} catch (e) {
// Restore to the previous state.
this._slider.value = oldVal;
this.commitProps({text: oldVal});
Component_A.popupEventError(e, 'syncInputData', logModule);
return;
}
// if (this.props.inputVar.func == Component_A.INPUTVAR_FUNC.CUSTOM) {
this._slider.value = value;
this.commitProps({text: value});
// }
if (this._props.onPointerRelease) {
try {
var fn = Component_A.genFuncTemplate(this._props.onPointerRelease, this);
fn && (await fn(value));
} catch (e) {
Component_A.popupEventError(e, 'onPointerRelease', logModule);
}
}
}
}
/**
* @description Generates the markup for the slider component.
* @member TComponents.VarSlider#markup
* @method
* @returns {string} HTML markup string
*/
markup() {
return /*html*/ `
<div class="tc-var-slider">
<div class="tc-slider"></div>
</div>
`;
}
/**
* @returns {string|number}
*/
get text() {
return this._props.text;
}
/**
* @description Set current text value
* @member {number} TComponents.VarSlider#text
* @instance
* @param {string|number} t - The text value to be set
* @throws {Error}
* @example
* const slider = new TComponents.VarSlider(document.body,{
* position: 'absolute',
* zIndex: 1000,
* });
*
* // Render the component.
* slider.render();
*
* // Set the text.
* slider.text = 20;
*/
set text(t) {
try {
if (typeof t === 'number') {
const validValue = this.checkValueInRange(t);
this.commitProps({text: validValue, value: validValue});
this._slider.value = validValue;
} else if (typeof t === 'string') {
if (t === '') return;
let tmp = Number(t);
if (typeof tmp === 'number' && !isNaN(tmp)) {
const validValue = this.checkValueInRange(tmp);
this.commitProps({text: validValue, value: validValue});
this._slider.value = validValue;
}
} else {
throw new Error(ErrorCode.FailedToSetText);
}
} catch (error) {
Logger.e(logModule, ErrorCode.FailedToSetText, `Invalid text data for component ${this.compId}.`, t);
throw new Error(ErrorCode.FailedToSetText, {cause: error});
}
}
/**
* @description Check if the value is in the range of min and max
* @member TComponents.VarSlider#checkValueInRange
* @method
* @param {number} value - The value to be checked
* @returns {number} - The valid value within the range
*/
checkValueInRange(value) {
if (value > this.max || value < this.min) {
Logger.w(
logModule,
ErrorCode.FailedToSetNum,
'The value parameter must be between the min value and the max value.',
value,
);
if (value > this.max) {
return this.max;
}
if (value < this.min) {
return this.min;
}
}
return value;
}
}
/**
* @description Add css properties to the component
* @member TComponents.VarSlider.loadCssClassFromString
* @method
* @static
* @param {string} css - The css string to be loaded into style tag
* @returns {void}
* @example
* TComponents.VarSlider.loadCssClassFromString(`
* .tc-var-slider {
* height: inherit;
* }`
* );
*/
VarSlider.loadCssClassFromString(/*css*/ `
.tc-var-slider {
height: inherit;
width: 100%;
min-width: 0px;
min-height: 0px;
padding: 0px;
margin: 0px;
}
`);