import _ from 'lodash';
import '../../../assert/js/assert.js';
import '../../../globals.js';
// Copyright 2017-2024, University of Colorado Boulder
/**
 * A trait for subtypes of Node, used to make the Node behave like a 'slider' with assistive technology. This could be
 * used by anything that moves along a 1-D line. An accessible slider behaves like:
 *
 * - Arrow keys increment/decrement the slider by a specified step size.
 * - Holding shift with arrow keys will increment/decrement by alternative step size, usually smaller than default.
 * - Page Up and Page Down increments/decrements value by an alternative step size, usually larger than default.
 * - Home key sets value to its minimum.
 * - End key sets value to its maximum.
 *
 * @author Jesse Greenberg (PhET Interactive Simulations)
 */
import assertHasProperties from '../../../phet-core/js/assertHasProperties.js';
import { DelayedMutate } from '../../../scenery/js/imports.js';
import sun from '../sun.js';
import AccessibleValueHandler from './AccessibleValueHandler.js';
const ACCESSIBLE_SLIDER_OPTIONS = [
    'startDrag',
    'drag',
    'endDrag'
];
/**
 * @param Type
 * @param optionsArgPosition - zero-indexed number that the options argument is provided at in the constructor for Type
 */
const AccessibleSlider = (Type, optionsArgPosition) => {
    const AccessibleSliderClass = DelayedMutate('AccessibleSlider', ACCESSIBLE_SLIDER_OPTIONS, class AccessibleSlider extends AccessibleValueHandler(Type, optionsArgPosition) {
        constructor(...args) {
            const providedOptions = args[optionsArgPosition];
            assert && providedOptions && assert(Object.getPrototypeOf(providedOptions) === Object.prototype, 'Extra prototype on AccessibleSlider options object is a code smell (or probably a bug)');
            // AccessibleSlider uses 'drag' terminology rather than 'change' for consistency with Slider
            assert && assert(providedOptions.startInput === undefined, 'AccessibleSlider sets startInput through options.startDrag');
            assert && assert(providedOptions.endInput === undefined, 'AccessibleSlider sets endInput through options.endDrag');
            assert && assert(providedOptions.onInput === undefined, 'AccessibleSlider sets onInput through options.drag');
            super(...args);
            this._startDrag = _.noop;
            this._drag = _.noop;
            this._endDrag = _.noop;
            // members of the Node API that are used by this trait
            assertHasProperties(this, ['addInputListener', 'removeInputListener']);
            // handle all accessible event input
            const accessibleInputListener = this.getAccessibleValueHandlerInputListener();
            this.addInputListener(accessibleInputListener);
            // called by disposeAccessibleSlider to prevent memory leaks
            this._disposeAccessibleSlider = () => {
                this.removeInputListener(accessibleInputListener);
            };
        }
        set startDrag(value) {
            this._startDrag = value;
            // Also (unfortunately) forwarding to the startInput
            this.startInput = value;
        }
        get startDrag() {
            return this._startDrag;
        }
        set drag(value) {
            this._drag = value;
            // Also (unfortunately) forwarding to the onInput
            this.onInput = value;
        }
        get drag() {
            return this._drag;
        }
        set endDrag(value) {
            this._endDrag = value;
            // Also (unfortunately) forwarding to the endInput
            this.endInput = value;
        }
        get endDrag() {
            return this._endDrag;
        }
        /**
         * Make the accessible slider portions of this node eligible for garbage collection. Call when disposing
         * the type that this trait is mixed into.
         */
        dispose() {
            this._disposeAccessibleSlider();
            super.dispose();
        }
    });
    /**
     * {Array.<string>} - String keys for all the allowed options that will be set by Node.mutate( options ), in
     * the order they will be evaluated.
     *
     * NOTE: See Node's _mutatorKeys documentation for more information on how this operates, and potential special
     *       cases that may apply.
     */
    AccessibleSliderClass.prototype._mutatorKeys = ACCESSIBLE_SLIDER_OPTIONS.concat(AccessibleSliderClass.prototype._mutatorKeys);
    assert && assert(AccessibleSliderClass.prototype._mutatorKeys.length === _.uniq(AccessibleSliderClass.prototype._mutatorKeys).length, 'duplicate mutator keys in AccessibleSlider');
    return AccessibleSliderClass;
};
sun.register('AccessibleSlider', AccessibleSlider);
export default AccessibleSlider;
//# sourceMappingURL=AccessibleSlider.js.map