| 23 | |
| 24 | /** Controls the state of a listbox. */ |
| 25 | export class ListboxPattern<V> { |
| 26 | readonly listBehavior: List<OptionPattern<V>, V>; |
| 27 | |
| 28 | /** Whether the listbox has been interacted with. */ |
| 29 | readonly hasBeenInteracted = signal(false); |
| 30 | |
| 31 | /** Whether the list is vertically or horizontally oriented. */ |
| 32 | readonly orientation: SignalLike<'vertical' | 'horizontal'>; |
| 33 | |
| 34 | /** Whether the listbox is disabled. */ |
| 35 | readonly disabled = computed(() => this.listBehavior.disabled()); |
| 36 | |
| 37 | /** Whether the listbox is readonly. */ |
| 38 | readonly readonly: SignalLike<boolean>; |
| 39 | |
| 40 | /** The tab index of the listbox. */ |
| 41 | readonly tabIndex: SignalLike<-1 | 0> = computed(() => this.listBehavior.tabIndex()); |
| 42 | |
| 43 | /** The id of the current active item. */ |
| 44 | readonly activeDescendant = computed(() => this.listBehavior.activeDescendant()); |
| 45 | |
| 46 | /** Whether multiple items in the list can be selected at once. */ |
| 47 | multi: SignalLike<boolean>; |
| 48 | |
| 49 | /** The number of items in the listbox. */ |
| 50 | readonly setsize = computed(() => this.inputs.items().length); |
| 51 | |
| 52 | /** Whether the listbox selection follows focus. */ |
| 53 | readonly followFocus = computed(() => this.inputs.selectionMode() === 'follow'); |
| 54 | |
| 55 | /** Whether the listbox should wrap. Used to disable wrapping while range selecting. */ |
| 56 | readonly wrap = signal(true); |
| 57 | |
| 58 | /** The key used to navigate to the previous item in the list. */ |
| 59 | readonly prevKey = computed(() => { |
| 60 | if (this.inputs.orientation() === 'vertical') { |
| 61 | return 'ArrowUp'; |
| 62 | } |
| 63 | return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; |
| 64 | }); |
| 65 | |
| 66 | /** The key used to navigate to the next item in the list. */ |
| 67 | readonly nextKey = computed(() => { |
| 68 | if (this.inputs.orientation() === 'vertical') { |
| 69 | return 'ArrowDown'; |
| 70 | } |
| 71 | return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; |
| 72 | }); |
| 73 | |
| 74 | /** Represents the space key. Does nothing when the user is actively using typeahead. */ |
| 75 | readonly dynamicSpaceKey = computed(() => (this.listBehavior.isTyping() ? '' : ' ')); |
| 76 | |
| 77 | /** The regexp used to decide if a key should trigger typeahead. */ |
| 78 | readonly typeaheadRegexp = /^.$/; |
| 79 | |
| 80 | /** The keydown event manager for the listbox. */ |
| 81 | readonly keydown = computed(() => { |
| 82 | const manager = new KeyboardEventManager(); |
nothing calls this directly
no test coverage detected