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