@penn-libraries/web 1.1.0-dev.6 → 1.1.0-dev.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,6 +12,12 @@ const Autocomplete = class {
12
12
  this.currentIndex = -1;
13
13
  this.originalValue = '';
14
14
  this.options = [];
15
+ this.keyHandlerMap = {
16
+ 'Escape': () => this.handleEscape(),
17
+ 'ArrowDown': () => this.handleArrowDown(),
18
+ 'ArrowUp': () => this.handleArrowUp(),
19
+ 'Enter': () => this.handleEnter()
20
+ };
15
21
  this.handleOptionClick = (index) => {
16
22
  this.currentIndex = index;
17
23
  this.selectCurrent();
@@ -63,7 +69,12 @@ const Autocomplete = class {
63
69
  if (!this.for)
64
70
  return null;
65
71
  const slot = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('slot[name="start"]');
66
- const input = slot.assignedElements()[0].querySelector(`input#${this.for}`);
72
+ if (!slot)
73
+ return null;
74
+ const assignedElements = slot.assignedElements();
75
+ if (assignedElements.length === 0)
76
+ return null;
77
+ const input = assignedElements[0].querySelector(`input#${this.for}`);
67
78
  return input || null;
68
79
  }
69
80
  isInputFocused() {
@@ -122,35 +133,33 @@ const Autocomplete = class {
122
133
  return;
123
134
  if (event.metaKey || event.ctrlKey)
124
135
  return; // Ignore keyboard shortcuts
125
- const handler = this.keyHandlers()[event.key];
136
+ const handler = this.keyHandlerMap[event.key];
126
137
  if (handler) {
127
- event.preventDefault();
138
+ // Don't prevent default for Enter - allow form submission
139
+ if (event.key !== 'Enter') {
140
+ event.preventDefault();
141
+ }
128
142
  handler();
129
143
  }
130
144
  }
131
- keyHandlers() {
132
- return {
133
- 'Escape': () => this.handleEscape(),
134
- 'ArrowDown': () => this.handleArrowDown(),
135
- 'ArrowUp': () => this.handleArrowUp(),
136
- 'Enter': () => this.handleEnter()
137
- };
138
- }
139
145
  handleEscape() {
140
146
  this.reset();
141
147
  this.syncInputState();
148
+ this.syncInputValueToSelection();
142
149
  }
143
150
  handleArrowDown() {
144
151
  if (!this.showSuggestions)
145
152
  return;
146
153
  this.moveNext();
147
154
  this.syncInputState();
155
+ this.syncInputValueToSelection();
148
156
  }
149
157
  handleArrowUp() {
150
158
  if (!this.showSuggestions)
151
159
  return;
152
160
  this.movePrevious();
153
161
  this.syncInputState();
162
+ this.syncInputValueToSelection();
154
163
  }
155
164
  handleEnter() {
156
165
  if (this.canSelect())
@@ -190,7 +199,6 @@ const Autocomplete = class {
190
199
  if (input)
191
200
  this.originalValue = input.value;
192
201
  this.showSuggestionsPanel();
193
- this.syncInputState();
194
202
  }
195
203
  showSuggestionsPanel() {
196
204
  this.showSuggestions = true;
@@ -199,8 +207,11 @@ const Autocomplete = class {
199
207
  closeSuggestions() {
200
208
  this.reset();
201
209
  this.syncInputState();
210
+ this.syncInputValueToSelection();
202
211
  }
203
212
  deferCloseSuggestions() {
213
+ if (this.blurTimeout)
214
+ clearTimeout(this.blurTimeout);
204
215
  this.blurTimeout = setTimeout(() => {
205
216
  if (this.isFocusOutsideComponent())
206
217
  this.closeSuggestions();
@@ -227,30 +238,34 @@ const Autocomplete = class {
227
238
  return;
228
239
  this.updateAriaExpanded(input);
229
240
  this.updateAriaActiveDescendant(input);
230
- this.updateInputValue(input);
241
+ }
242
+ syncInputValueToSelection() {
243
+ const input = this.getInput();
244
+ if (!input)
245
+ return;
246
+ input.value = this.currentIndex >= 0 && this.currentIndex < this.options.length
247
+ ? this.options[this.currentIndex].value
248
+ : this.originalValue;
231
249
  }
232
250
  updateAriaExpanded(input) {
233
251
  input.setAttribute('aria-expanded', this.showSuggestions.toString());
234
252
  }
235
253
  updateAriaActiveDescendant(input) {
236
- const hasSelection = this.showSuggestions && this.currentIndex >= 0;
237
- if (hasSelection && this.options[this.currentIndex]) {
254
+ const hasSelection = this.showSuggestions &&
255
+ this.currentIndex >= 0 &&
256
+ this.currentIndex < this.options.length;
257
+ if (hasSelection) {
238
258
  input.setAttribute('aria-activedescendant', this.options[this.currentIndex].id);
239
259
  }
240
260
  else {
241
261
  input.removeAttribute('aria-activedescendant');
242
262
  }
243
263
  }
244
- updateInputValue(input) {
245
- input.value = this.currentIndex >= 0
246
- ? this.options[this.currentIndex].value
247
- : this.originalValue;
248
- }
249
264
  shouldShowListbox() {
250
265
  return this.showSuggestions && this.options.length > 0 && this.isInputFocused();
251
266
  }
252
267
  render() {
253
- return (index.h("div", { key: '71422b55533372a9d8697e648e49f87fe223f4e0' }, index.h("slot", { key: '951511fd2090b9816c2e6c1a5a40169ea08e72fd', name: "start" }), this.shouldShowListbox() && (index.h("ol", { key: 'e3f6f14686bc99b6e25d34d8e053f01174f23438', role: "listbox", id: "listbox" }, this.options.map((option, index$1) => (index.h("li", { role: "option", id: option.id, "aria-selected": this.currentIndex === index$1 ? 'true' : 'false', tabindex: "-1", onClick: () => this.handleOptionClick(index$1), innerHTML: option.html })))))));
268
+ return (index.h("div", { key: 'd7c11d48e354937eedc76f608ef3b3b8762ddb4b' }, index.h("slot", { key: 'a3c65cf477aa9f575c3310e364c1dd2a5dca9e57', name: "start" }), this.shouldShowListbox() && (index.h("ol", { key: 'dc035d276f14da3ad0246924c345bc86ff5c68f9', role: "listbox", id: "listbox" }, this.options.map((option, index$1) => (index.h("li", { role: "option", id: option.id, "aria-selected": this.currentIndex === index$1 ? 'true' : 'false', tabindex: "-1", onClick: () => this.handleOptionClick(index$1), innerHTML: option.html })))))));
254
269
  }
255
270
  get el() { return index.getElement(this); }
256
271
  };