From 3dfd32fbc38e80182f71cb9c75eeefa18adae52b Mon Sep 17 00:00:00 2001 From: Nagashri Date: Tue, 4 Nov 2025 14:18:12 +0530 Subject: [PATCH 1/3] chore: elaborated inline comments for CheckBox.js [AC-43] --- test-app/src/widgets/CheckBox.js | 43 +++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/test-app/src/widgets/CheckBox.js b/test-app/src/widgets/CheckBox.js index b028e84..84b0d94 100644 --- a/test-app/src/widgets/CheckBox.js +++ b/test-app/src/widgets/CheckBox.js @@ -1,12 +1,25 @@ import AccessibilityModule from '@curriculumassociates/createjs-accessibility'; +/** + * A custom checkbox component that implements accessibility features. + * This class creates a visually appealing and fully accessible checkbox + * with proper focus indicators and ARIA attributes. + */ export default class CheckBox extends createjs.Container { + /** + * Creates a new CheckBox instance. + * @param {number} width - The width of the checkbox + * @param {number} height - The height of the checkbox + * @param {number} tabIndex - The tab order of the checkbox for keyboard navigation + * @param {Function} callBack - Optional callback function triggered when checkbox state changes + */ constructor(width, height, tabIndex, callBack = () => {}) { super(); this.width = width; this.height = height; this.callBack = callBack; this.checked = false; + // Register the checkbox with accessibility module to enable screen reader support AccessibilityModule.register({ accessibleOptions: { tabIndex }, displayObject: this, @@ -33,12 +46,23 @@ export default class CheckBox extends createjs.Container { this._createAsset(); } + /** + * Creates the visual assets for the checkbox by adding the box area and checkmark + * @private + */ _createAsset() { this._addBoxArea(); this._addCheckMark(); } + /** + * Creates the main checkbox container and focus indicator + * The checkbox has a light gray fill with a dark border + * Focus indicator is a blue outline that appears when the checkbox gains focus + * @private + */ _addBoxArea() { + // Create the main checkbox container with a gray fill and dark border const box = new createjs.Shape(); box.graphics .setStrokeStyle(1) @@ -48,6 +72,7 @@ export default class CheckBox extends createjs.Container { box.setBounds(0, 0, this.width, this.height); this.addChild(box); + // Create a focus indicator that appears when the checkbox is focused const focusRect = new createjs.Shape(); focusRect.graphics .setStrokeStyle(5) @@ -60,6 +85,11 @@ export default class CheckBox extends createjs.Container { this.focusRect = focusRect; } + /** + * Creates the checkmark symbol that appears when the checkbox is checked + * The checkmark is a thick line drawn in a check symbol shape + * @private + */ _addCheckMark() { const checkMark = new createjs.Shape(); checkMark.graphics @@ -70,12 +100,17 @@ export default class CheckBox extends createjs.Container { .lineTo(this.width - 6, 0); this.addChild(checkMark); + // Position the checkmark with slight offset for better visual alignment checkMark.set({ x: 2, y: 2 }); checkMark.visible = false; this.checkMark = checkMark; } + /** + * Handles state changes when the checkbox is clicked or activated via keyboard + * Updates the visual state and accessibility properties + */ onChange() { this.accessible.requestFocus(); this.checked = !this.checked; @@ -84,11 +119,17 @@ export default class CheckBox extends createjs.Container { this.callBack(); } + /** + * Shows the focus indicator when the checkbox receives focus + */ onFocus() { this.focusRect.visible = true; } + /** + * Hides the focus indicator when the checkbox loses focus + */ onBlur() { this.focusRect.visible = false; } -} +} \ No newline at end of file From 6212adf7c90107152380474eafb9b3ab6947180c Mon Sep 17 00:00:00 2001 From: Nagashri Date: Tue, 4 Nov 2025 14:19:08 +0530 Subject: [PATCH 2/3] chore: elaborated inline comments for ClearInputButton.js [AC-43] --- test-app/src/widgets/ClearInputButton.js | 44 +++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/test-app/src/widgets/ClearInputButton.js b/test-app/src/widgets/ClearInputButton.js index 8d7f8e9..d240308 100644 --- a/test-app/src/widgets/ClearInputButton.js +++ b/test-app/src/widgets/ClearInputButton.js @@ -1,31 +1,67 @@ import _, { noop } from 'lodash'; import Button from './Button'; +/** + * ClearInputButton extends Button to create a circular button with an 'x' symbol + * commonly used for clearing input fields. This component inherits accessibility + * features from the base Button class and customizes the visual appearance. + */ export default class ClearInputButton extends Button { + /** + * Creates a new ClearInputButton instance + * @param {Object} options - Configuration options for the button + * @param {number} tabIndex - The tab order index for keyboard navigation + * @param {Function} callBack - Optional callback function triggered on button click (defaults to no-op) + */ constructor(options, tabIndex, callBack = _.noop) { super(options, tabIndex, callBack); } + /** + * Creates a circular background for the button + * @param {string} color - The fill color for the button background + * @private + */ _fillBackground(color) { this.background.graphics .beginFill(color) .drawCircle(0, 0, this.height * 0.5); } + /** + * Override mouse down handler to prevent default behavior + * This maintains consistent appearance during mouse interaction + * @private + */ _onMouseDown() { noop(); } + /** + * Override mouse up handler to prevent default behavior + * This maintains consistent appearance during mouse interaction + * @private + */ _onMouseUp() { noop(); } + /** + * Creates and adds the circular grey background to the button + * This provides the base visual element for the clear button + * @private + */ _addBackground() { this.background = new createjs.Shape(); this._fillBackground('grey'); this.addChild(this.background); } + /** + * Creates and adds the focus indicator ring around the button + * The indicator is a black circle that appears when the button is focused + * @private + */ _addFocusIndicator() { this.focusIndicator = new createjs.Shape(); this.focusIndicator.name = 'focusIndicator'; @@ -37,13 +73,19 @@ export default class ClearInputButton extends Button { this.focusIndicator.visible = false; } + /** + * Creates and adds the 'x' symbol text to the button + * The text is centered within the button using the button height for sizing + * @private + */ _addText() { this.text = new createjs.Text('x', `${this.height}px Arial`, 'white'); const textBounds = this.text.getBounds(); + // Center the text both horizontally and vertically this.text.set({ x: -(textBounds.width * 0.5), y: -(textBounds.height * 0.5), }); this.addChild(this.text); } -} +} \ No newline at end of file From 7d71c440d081e0dace9e17c772e92e58c8acdadf Mon Sep 17 00:00:00 2001 From: Nagashri Date: Tue, 4 Nov 2025 14:20:46 +0530 Subject: [PATCH 3/3] chore: elaborated inline comments for ComboBox.js [AC-43] --- test-app/src/widgets/ComboBox.js | 114 +++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 15 deletions(-) diff --git a/test-app/src/widgets/ComboBox.js b/test-app/src/widgets/ComboBox.js index 4d6f79b..a8a6fc3 100644 --- a/test-app/src/widgets/ComboBox.js +++ b/test-app/src/widgets/ComboBox.js @@ -4,10 +4,19 @@ import AccessibilityModule from '@curriculumassociates/createjs-accessibility'; import SingleLineTextInput from './SingleLineTextInput'; /** - * A combobox that allows the user to enter whatever they like and the listbox - * part is suggested values + * A combobox component that combines a text input with a dropdown list. + * This implementation supports both free text entry and selection from a predefined list, + * making it flexible for various use cases. The component is fully accessible with + * keyboard navigation and screen reader support. */ export default class ComboBox extends createjs.Container { + /** + * Creates a new ComboBox instance + * @param {Array} options - Array of options to display in the dropdown + * @param {number} width - Width of the combobox + * @param {number} height - Height of the combobox + * @param {number} tabIndex - Tab order index for keyboard navigation + */ constructor(options, width, height, tabIndex) { super(); _.bindAll( @@ -20,6 +29,7 @@ export default class ComboBox extends createjs.Container { '_onDropDownKeyDown', '_onValueChanged' ); + // Register with accessibility module for screen reader and keyboard support AccessibilityModule.register({ displayObject: this, role: AccessibilityModule.ROLES.COMBOBOX, @@ -32,10 +42,15 @@ export default class ComboBox extends createjs.Container { this._createCollapsedView(width, height, tabIndex); this._createDropDownView(width, height); + // Link the textbox with the dropdown for accessibility this._textBox.accessible.controls = this._dropDownView; this._dropDownView.visible = false; } + /** + * Sets whether the combobox can receive keyboard focus + * @param {boolean} tabbable - Whether the combobox should be focusable + */ setTabbable(tabbable) { if (tabbable) { this._textBox.accessible.tabIndex = 0; @@ -44,19 +59,32 @@ export default class ComboBox extends createjs.Container { } } + /** + * Gets the current text value of the combobox + * @returns {string} The current text in the input field + */ get text() { return this._textBox.text; } + /** + * Sets the text value of the combobox + * @param {string} str - The text to set + */ set text(str) { this._textBox.text = str; } + /** + * Creates the collapsed (default) view of the combobox + * This includes a text input field and a dropdown arrow button + * @private + */ _createCollapsedView(width, height, tabIndex) { - // since the arrow for opening the drop down is a square based on the height, calculate - // the text box width + // Calculate text box width to accommodate the dropdown arrow const textBoxWidth = width - height; + // Create and setup the text input component this._textBox = new SingleLineTextInput(textBoxWidth, height, tabIndex); this._textBox.enableKeyEvents = true; this._textBox.addEventListener('keydown', this._onCollapedViewKeyDown); @@ -65,19 +93,25 @@ export default class ComboBox extends createjs.Container { this.addChild(this._textBox); this.accessible.addChild(this._textBox); + // Create the dropdown arrow button this._arrow = new createjs.Shape(); - this._arrow.graphics.beginFill('#aaaaaa').drawRect(0, 0, height, height); // background + // Create grey background for the arrow button + this._arrow.graphics.beginFill('#aaaaaa').drawRect(0, 0, height, height); + // Draw the arrow symbol this._arrow.graphics .endFill() .beginStroke('#000000') .moveTo(height * 0.25, height * 0.25) .lineTo(height * 0.5, height * 0.75) - .lineTo(height * 0.75, height * 0.25); // arrow + .lineTo(height * 0.75, height * 0.25); + // Add button border this._arrow.graphics .beginStroke('#000000') .setStrokeStyle(1) - .drawRect(0, 0, height, height); // border + .drawRect(0, 0, height, height); this._arrow.x = width - height; + + // Register the arrow button with accessibility features AccessibilityModule.register({ displayObject: this._arrow, role: AccessibilityModule.ROLES.BUTTON, @@ -91,13 +125,17 @@ export default class ComboBox extends createjs.Container { this.accessible.addChild(this._arrow); } + /** + * Handles clicks on the collapsed view (mainly the dropdown arrow) + * Toggles the visibility of the dropdown list + * @private + */ _onCollapedViewClick(evt) { this._textBox.accessible.requestFocus(); this._dropDownView.visible = !this._dropDownView.visible; this.accessible.expanded = this._dropDownView.visible; if (this._dropDownView.visible) { - // make sure the listbox is on top of its sibling DisplayObjects to try - // to ensure that the dropdown is completely visible + // Ensure dropdown is visible by bringing it to the front this.parent.addChild(this); } else { this._textBox.accessible.active = undefined; @@ -107,13 +145,17 @@ export default class ComboBox extends createjs.Container { evt.preventDefault(); } + /** + * Handles keyboard events in the collapsed view + * Supports up/down arrow keys for dropdown navigation + * @private + */ _onCollapedViewKeyDown(evt) { if (evt.keyCode === KeyCodes.down || evt.keyCode === KeyCodes.up) { this._dropDownView.visible = true; this.accessible.expanded = true; - // make sure the listbox is on top of its sibling DisplayObjects to try - // to ensure that the dropdown is completely visible + // Ensure dropdown is visible by bringing it to the front this.parent.addChild(this); this._dropDownView.accessible.requestFocus(); @@ -126,6 +168,12 @@ export default class ComboBox extends createjs.Container { } } + /** + * Gets the next or previous option in the dropdown list + * @param {boolean} next - True to get next option, false for previous + * @returns {Object} The adjacent option object + * @private + */ _getAdjacentOption(next) { let index = _.findIndex(this._options, (child) => child.selected); if (next) { @@ -137,6 +185,12 @@ export default class ComboBox extends createjs.Container { return this._options[index]; } + /** + * Updates the selected option in the dropdown + * Updates the text input and accessibility properties + * @param {Object} option - The option to select + * @private + */ _updateSelectedOption(option) { this._options.forEach((opt) => { opt.selected = false; @@ -149,6 +203,11 @@ export default class ComboBox extends createjs.Container { this._dropDownView.accessible.selected = option; } + /** + * Handles changes to the input text + * Updates option selection if text matches an option + * @private + */ _onCollapedViewChange(evt) { _.forEach(this._options, (opt) => { opt.selected = false; @@ -162,12 +221,18 @@ export default class ComboBox extends createjs.Container { } } + /** + * Creates the dropdown view containing the list of options + * Sets up the container, background, and options list + * @private + */ _createDropDownView(width, optionHeight) { this._dropDownView = new createjs.Container(); this._dropDownView.y = optionHeight; this._dropDownView.visible = false; this.addChild(this._dropDownView); + // Register dropdown with accessibility features AccessibilityModule.register({ displayObject: this._dropDownView, role: AccessibilityModule.ROLES.SINGLESELECTLISTBOX, @@ -181,6 +246,7 @@ export default class ComboBox extends createjs.Container { this._dropDownView.addEventListener('valueChanged', this._onValueChanged); this._dropDownView.addEventListener('blur', this._onDropDownViewBlur); + // Create dropdown background const bg = new createjs.Shape(); bg.graphics .beginStroke('#000000') @@ -189,6 +255,7 @@ export default class ComboBox extends createjs.Container { .drawRect(0, 0, width, optionHeight * this._options.length); this._dropDownView.addChild(bg); + // Add options to the dropdown this._options.forEach((option, i) => { option.y = optionHeight * i; option.addEventListener('click', this._onOptionClick); @@ -197,19 +264,31 @@ export default class ComboBox extends createjs.Container { }); } + /** + * Handles clicks on dropdown options + * Updates the text input and closes the dropdown + * @private + */ _onOptionClick(evt) { - // set the text field to the value of the option this._textBox.text = evt.currentTarget._label.text; - - // close the dropdown this._onCollapedViewClick(evt); } + /** + * Handles blur events on the dropdown + * Closes the dropdown when focus is lost + * @private + */ _onDropDownViewBlur() { this._dropDownView.visible = false; this.accessible.expanded = this._dropDownView.visible; } + /** + * Handles keyboard events in the dropdown view + * Supports Enter to select and Escape to close + * @private + */ _onDropDownKeyDown(evt) { if (evt.keyCode === KeyCodes.enter || evt.keyCode === KeyCodes.esc) { this._textBox.accessible.requestFocus(); @@ -219,7 +298,12 @@ export default class ComboBox extends createjs.Container { } } + /** + * Handles value changes in the dropdown + * Updates the selected option when changed + * @private + */ _onValueChanged(evt) { this._updateSelectedOption(evt.selectedDisplayObject); } -} +} \ No newline at end of file