From 1210f0a4f8971e7db38880f6c25216e33697a557 Mon Sep 17 00:00:00 2001 From: Sam Reid Date: Tue, 28 May 2024 17:38:00 -0600 Subject: [PATCH] Make RectangularRadioButton.options.accessibleName default based on a tandem name, if it is supplied, see https://github.com/phetsims/buoyancy/issues/109 --- js/Tandem.ts | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/js/Tandem.ts b/js/Tandem.ts index 6fb5425..454ce57 100644 --- a/js/Tandem.ts +++ b/js/Tandem.ts @@ -11,9 +11,10 @@ import arrayRemove from '../../phet-core/js/arrayRemove.js'; import merge from '../../phet-core/js/merge.js'; import optionize from '../../phet-core/js/optionize.js'; -import PhetioObject from './PhetioObject.js'; +import PhetioObject, { PhetioObjectOptions } from './PhetioObject.js'; import TandemConstants, { PhetioID } from './TandemConstants.js'; import tandemNamespace from './tandemNamespace.js'; +import PickOptional from '../../phet-core/js/types/PickOptional.js'; // constants // Tandem can't depend on joist, so cannot use packageJSON module @@ -597,6 +598,32 @@ class Tandem { * Use this as the parent tandem for Properties that are related to sim-specific preferences. */ public static readonly PREFERENCES = Tandem.GLOBAL_MODEL.createTandem( 'preferences' ); + + /** + * Convenience method to get an accessibleName from providedOptions, see tandemNameToAccessibleName + */ + public static toAccessibleName( providedOptions: PickOptional | undefined, suffix: string ): string | null { + if ( providedOptions && providedOptions.tandem && providedOptions.tandem.supplied ) { + return Tandem.tandemNameToAccessibleName( providedOptions.tandem.name, suffix ); + } + return null; + } + + /** + * Tandem names can be used to create accessible names for screen readers. This method will convert a tandem name to + * a human-readable name. For example, 'resetAllButton' would become 'Reset All'. + */ + public static tandemNameToAccessibleName( tandemName: string, suffix: string ): string | null { + assert && assert( tandemName.toLowerCase().endsWith( suffix.toLowerCase() ), `suffix should be at the end of the tandem name: ${tandemName}` ); + + // trim the suffix + const withoutSuffix = tandemName.slice( 0, -suffix.length ); + + const whitespaceName = withoutSuffix.replace( /([A-Z])/g, ' $1' ).trim(); + + // capitalize the first letter of each word, no matter how many words + return whitespaceName.replace( /\b\w/g, c => c.toUpperCase() ); + } } Tandem.addLaunchListener( () => {