@@ -23,6 +23,7 @@ import {
2323} from './field.js' ;
2424import * as fieldRegistry from './field_registry.js' ;
2525import { Menu } from './menu.js' ;
26+ import { MenuSeparator } from './menu_separator.js' ;
2627import { MenuItem } from './menuitem.js' ;
2728import * as aria from './utils/aria.js' ;
2829import { Coordinate } from './utils/coordinate.js' ;
@@ -35,14 +36,10 @@ import {Svg} from './utils/svg.js';
3536 * Class for an editable dropdown field.
3637 */
3738export class FieldDropdown extends Field < string > {
38- /** Horizontal distance that a checkmark overhangs the dropdown. */
39- static CHECKMARK_OVERHANG = 25 ;
40-
4139 /**
42- * Maximum height of the dropdown menu, as a percentage of the viewport
43- * height.
40+ * Magic constant used to represent a separator in a list of dropdown items.
4441 */
45- static MAX_MENU_HEIGHT_VH = 0.45 ;
42+ static readonly SEPARATOR = 'separator' ;
4643
4744 static ARROW_CHAR = '▾' ;
4845
@@ -323,7 +320,13 @@ export class FieldDropdown extends Field<string> {
323320 const options = this . getOptions ( false ) ;
324321 this . selectedMenuItem = null ;
325322 for ( let i = 0 ; i < options . length ; i ++ ) {
326- const [ label , value ] = options [ i ] ;
323+ const option = options [ i ] ;
324+ if ( option === FieldDropdown . SEPARATOR ) {
325+ menu . addChild ( new MenuSeparator ( ) ) ;
326+ continue ;
327+ }
328+
329+ const [ label , value ] = option ;
327330 const content = ( ( ) => {
328331 if ( typeof label === 'object' ) {
329332 // Convert ImageProperties to an HTMLImageElement.
@@ -667,7 +670,10 @@ export class FieldDropdown extends Field<string> {
667670 suffix ?: string ;
668671 } {
669672 let hasImages = false ;
670- const trimmedOptions = options . map ( ( [ label , value ] ) : MenuOption => {
673+ const trimmedOptions = options . map ( ( option ) : MenuOption => {
674+ if ( option === FieldDropdown . SEPARATOR ) return option ;
675+
676+ const [ label , value ] = option ;
671677 if ( typeof label === 'string' ) {
672678 return [ parsing . replaceMessageReferences ( label ) , value ] ;
673679 }
@@ -748,28 +754,28 @@ export class FieldDropdown extends Field<string> {
748754 }
749755 let foundError = false ;
750756 for ( let i = 0 ; i < options . length ; i ++ ) {
751- const tuple = options [ i ] ;
752- if ( ! Array . isArray ( tuple ) ) {
757+ const option = options [ i ] ;
758+ if ( ! Array . isArray ( option ) && option !== FieldDropdown . SEPARATOR ) {
753759 foundError = true ;
754760 console . error (
755- `Invalid option[${ i } ]: Each FieldDropdown option must be an array.
756- Found: ${ tuple } ` ,
761+ `Invalid option[${ i } ]: Each FieldDropdown option must be an array or
762+ the string literal 'separator'. Found: ${ option } ` ,
757763 ) ;
758- } else if ( typeof tuple [ 1 ] !== 'string' ) {
764+ } else if ( typeof option [ 1 ] !== 'string' ) {
759765 foundError = true ;
760766 console . error (
761767 `Invalid option[${ i } ]: Each FieldDropdown option id must be a string.
762- Found ${ tuple [ 1 ] } in: ${ tuple } ` ,
768+ Found ${ option [ 1 ] } in: ${ option } ` ,
763769 ) ;
764770 } else if (
765- tuple [ 0 ] &&
766- typeof tuple [ 0 ] !== 'string' &&
767- typeof tuple [ 0 ] . src !== 'string'
771+ option [ 0 ] &&
772+ typeof option [ 0 ] !== 'string' &&
773+ typeof option [ 0 ] . src !== 'string'
768774 ) {
769775 foundError = true ;
770776 console . error (
771777 `Invalid option[${ i } ]: Each FieldDropdown option must have a string
772- label or image description. Found ${ tuple [ 0 ] } in: ${ tuple } ` ,
778+ label or image description. Found ${ option [ 0 ] } in: ${ option } ` ,
773779 ) ;
774780 }
775781 }
@@ -790,11 +796,12 @@ export interface ImageProperties {
790796}
791797
792798/**
793- * An individual option in the dropdown menu. The first element is the human-
794- * readable value (text or image), and the second element is the language-
795- * neutral value.
799+ * An individual option in the dropdown menu. Can be either the string literal
800+ * `separator` for a menu separator item, or an array for normal action menu
801+ * items. In the latter case, the first element is the human-readable value
802+ * (text or image), and the second element is the language-neutral value.
796803 */
797- export type MenuOption = [ string | ImageProperties , string ] ;
804+ export type MenuOption = [ string | ImageProperties , string ] | 'separator' ;
798805
799806/**
800807 * A function that generates an array of menu options for FieldDropdown
0 commit comments