@penn-libraries/web 1.1.0-dev.5 → 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.
@@ -1,6 +1,6 @@
1
1
  import { r as registerInstance, c as createEvent, h, a as getElement, g as getAssetPath } from './index-CE_ILdTo.js';
2
2
 
3
- const pennlibsAutocompleteCss = ":host {\n display: block;\n width: 100%;\n border-radius: 1.25rem;\n padding: 0;\n border-top: 0;\n position: relative;\n}\n\n[role=listbox] {\n position: absolute;\n margin-top: var(--pl-space-xs);\n background: var(--pl-color-bg-default);\n border-radius: 1.25rem;\n box-shadow: rgba(140, 149, 159, 0.3) 0px 8px 24px 0px;\n width: 100%;\n overflow: hidden;\n z-index: 1;\n\n display: flex;\n flex-direction: column;\n}\n\np {\n margin: 0;\n font-size: var(--pl-font-size-s);\n color: var(--pl-color-fg-subtle);\n padding: var(--pl-space-xs) calc(var(--pl-space-m) + var(--pl-space-2xs));\n font-size: var(--pl-font-size-s);\n order: 2;\n font-weight: 500;\n background: var(--pl-color-bg-subtle);\n border-radius: 0 0 1.25rem 1.25rem;\n\n display: flex;\n gap: var(--pl-space-s) var(--pl-space-l);\n flex-wrap: wrap;\n}\n\nol {\n list-style: none;\n margin: 0;\n padding: var(--pl-space-xs) 0;\n order: 1;\n}\n\n[role=option] {\n color: var(--pl-color-fg-default);\n padding: var(--pl-space-s) calc(var(--pl-space-m) + var(--pl-space-2xs));\n text-decoration: none;\n font-weight: 700; \n\n &:hover {\n cursor: pointer;\n }\n\n &:hover,\n &:focus {\n text-decoration-thickness: 2px;\n text-underline-offset: 2px;\n text-decoration: underline;\n }\n}\n\n[aria-selected=true] {\n text-decoration-thickness: 2px;\n text-underline-offset: 2px;\n text-decoration: underline;\n}\n\nmark {\n background: none;\n font-weight: 400;\n}\n\n.suggestion--border {\n border-bottom: solid 1px rgb(from var(--pl-color-fg-default) r g b / 0.2);\n padding-bottom: calc(var(--pl-space-2xs) + var(--pl-space-s));\n margin-bottom: var(--pl-space-2xs);\n}";
3
+ const pennlibsAutocompleteCss = ":host {\n display: block;\n width: 100%;\n border-radius: 1.25rem;\n padding: 0;\n border-top: 0;\n position: relative;\n}\n\n[role=listbox] {\n position: absolute;\n margin-top: var(--pl-space-xs);\n background: var(--pl-color-bg-default);\n border-radius: 1.25rem;\n box-shadow: rgba(140, 149, 159, 0.3) 0px 8px 24px 0px;\n width: 100%;\n overflow: hidden;\n z-index: 1;\n\n display: flex;\n flex-direction: column;\n}\n\np {\n margin: 0;\n font-size: var(--pl-font-size-s);\n color: var(--pl-color-fg-subtle);\n padding: var(--pl-space-xs) calc(var(--pl-space-m) + var(--pl-space-2xs));\n font-size: var(--pl-font-size-s);\n order: 2;\n font-weight: 500;\n background: var(--pl-color-bg-subtle);\n border-radius: 0 0 1.25rem 1.25rem;\n\n display: flex;\n gap: var(--pl-space-s) var(--pl-space-l);\n flex-wrap: wrap;\n}\n\nol {\n list-style: none;\n margin: 0;\n padding: var(--pl-space-xs) 0;\n order: 1;\n}\n\n[role=option] {\n color: var(--pl-color-fg-default);\n padding: var(--pl-space-s) calc(var(--pl-space-m) + var(--pl-space-2xs));\n text-decoration: none;\n font-weight: 700; \n\n &:hover {\n cursor: pointer;\n }\n\n &:hover,\n &:focus {\n text-decoration-thickness: 2px;\n text-underline-offset: 2px;\n text-decoration: underline;\n }\n}\n\n[aria-selected=true] {\n text-decoration-thickness: 2px;\n text-underline-offset: 2px;\n text-decoration: underline;\n}\n\nmark,\nb {\n background: none;\n font-weight: 400;\n}\n\n.suggestion--border {\n border-bottom: solid 1px rgb(from var(--pl-color-fg-default) r g b / 0.2);\n padding-bottom: calc(var(--pl-space-2xs) + var(--pl-space-s));\n margin-bottom: var(--pl-space-2xs);\n}";
4
4
 
5
5
  const Autocomplete = class {
6
6
  constructor(hostRef) {
@@ -10,6 +10,12 @@ const Autocomplete = class {
10
10
  this.currentIndex = -1;
11
11
  this.originalValue = '';
12
12
  this.options = [];
13
+ this.keyHandlerMap = {
14
+ 'Escape': () => this.handleEscape(),
15
+ 'ArrowDown': () => this.handleArrowDown(),
16
+ 'ArrowUp': () => this.handleArrowUp(),
17
+ 'Enter': () => this.handleEnter()
18
+ };
13
19
  this.handleOptionClick = (index) => {
14
20
  this.currentIndex = index;
15
21
  this.selectCurrent();
@@ -61,7 +67,12 @@ const Autocomplete = class {
61
67
  if (!this.for)
62
68
  return null;
63
69
  const slot = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('slot[name="start"]');
64
- const input = slot.assignedElements()[0].querySelector(`input#${this.for}`);
70
+ if (!slot)
71
+ return null;
72
+ const assignedElements = slot.assignedElements();
73
+ if (assignedElements.length === 0)
74
+ return null;
75
+ const input = assignedElements[0].querySelector(`input#${this.for}`);
65
76
  return input || null;
66
77
  }
67
78
  isInputFocused() {
@@ -120,35 +131,33 @@ const Autocomplete = class {
120
131
  return;
121
132
  if (event.metaKey || event.ctrlKey)
122
133
  return; // Ignore keyboard shortcuts
123
- const handler = this.keyHandlers()[event.key];
134
+ const handler = this.keyHandlerMap[event.key];
124
135
  if (handler) {
125
- event.preventDefault();
136
+ // Don't prevent default for Enter - allow form submission
137
+ if (event.key !== 'Enter') {
138
+ event.preventDefault();
139
+ }
126
140
  handler();
127
141
  }
128
142
  }
129
- keyHandlers() {
130
- return {
131
- 'Escape': () => this.handleEscape(),
132
- 'ArrowDown': () => this.handleArrowDown(),
133
- 'ArrowUp': () => this.handleArrowUp(),
134
- 'Enter': () => this.handleEnter()
135
- };
136
- }
137
143
  handleEscape() {
138
144
  this.reset();
139
145
  this.syncInputState();
146
+ this.syncInputValueToSelection();
140
147
  }
141
148
  handleArrowDown() {
142
149
  if (!this.showSuggestions)
143
150
  return;
144
151
  this.moveNext();
145
152
  this.syncInputState();
153
+ this.syncInputValueToSelection();
146
154
  }
147
155
  handleArrowUp() {
148
156
  if (!this.showSuggestions)
149
157
  return;
150
158
  this.movePrevious();
151
159
  this.syncInputState();
160
+ this.syncInputValueToSelection();
152
161
  }
153
162
  handleEnter() {
154
163
  if (this.canSelect())
@@ -188,7 +197,6 @@ const Autocomplete = class {
188
197
  if (input)
189
198
  this.originalValue = input.value;
190
199
  this.showSuggestionsPanel();
191
- this.syncInputState();
192
200
  }
193
201
  showSuggestionsPanel() {
194
202
  this.showSuggestions = true;
@@ -197,8 +205,11 @@ const Autocomplete = class {
197
205
  closeSuggestions() {
198
206
  this.reset();
199
207
  this.syncInputState();
208
+ this.syncInputValueToSelection();
200
209
  }
201
210
  deferCloseSuggestions() {
211
+ if (this.blurTimeout)
212
+ clearTimeout(this.blurTimeout);
202
213
  this.blurTimeout = setTimeout(() => {
203
214
  if (this.isFocusOutsideComponent())
204
215
  this.closeSuggestions();
@@ -225,30 +236,34 @@ const Autocomplete = class {
225
236
  return;
226
237
  this.updateAriaExpanded(input);
227
238
  this.updateAriaActiveDescendant(input);
228
- this.updateInputValue(input);
239
+ }
240
+ syncInputValueToSelection() {
241
+ const input = this.getInput();
242
+ if (!input)
243
+ return;
244
+ input.value = this.currentIndex >= 0 && this.currentIndex < this.options.length
245
+ ? this.options[this.currentIndex].value
246
+ : this.originalValue;
229
247
  }
230
248
  updateAriaExpanded(input) {
231
249
  input.setAttribute('aria-expanded', this.showSuggestions.toString());
232
250
  }
233
251
  updateAriaActiveDescendant(input) {
234
- const hasSelection = this.showSuggestions && this.currentIndex >= 0;
235
- if (hasSelection && this.options[this.currentIndex]) {
252
+ const hasSelection = this.showSuggestions &&
253
+ this.currentIndex >= 0 &&
254
+ this.currentIndex < this.options.length;
255
+ if (hasSelection) {
236
256
  input.setAttribute('aria-activedescendant', this.options[this.currentIndex].id);
237
257
  }
238
258
  else {
239
259
  input.removeAttribute('aria-activedescendant');
240
260
  }
241
261
  }
242
- updateInputValue(input) {
243
- input.value = this.currentIndex >= 0
244
- ? this.options[this.currentIndex].value
245
- : this.originalValue;
246
- }
247
262
  shouldShowListbox() {
248
263
  return this.showSuggestions && this.options.length > 0 && this.isInputFocused();
249
264
  }
250
265
  render() {
251
- return (h("div", { key: '71422b55533372a9d8697e648e49f87fe223f4e0' }, h("slot", { key: '951511fd2090b9816c2e6c1a5a40169ea08e72fd', name: "start" }), this.shouldShowListbox() && (h("ol", { key: 'e3f6f14686bc99b6e25d34d8e053f01174f23438', role: "listbox", id: "listbox" }, this.options.map((option, index) => (h("li", { role: "option", id: option.id, "aria-selected": this.currentIndex === index ? 'true' : 'false', tabindex: "-1", onClick: () => this.handleOptionClick(index), innerHTML: option.html })))))));
266
+ return (h("div", { key: 'd7c11d48e354937eedc76f608ef3b3b8762ddb4b' }, h("slot", { key: 'a3c65cf477aa9f575c3310e364c1dd2a5dca9e57', name: "start" }), this.shouldShowListbox() && (h("ol", { key: 'dc035d276f14da3ad0246924c345bc86ff5c68f9', role: "listbox", id: "listbox" }, this.options.map((option, index) => (h("li", { role: "option", id: option.id, "aria-selected": this.currentIndex === index ? 'true' : 'false', tabindex: "-1", onClick: () => this.handleOptionClick(index), innerHTML: option.html })))))));
252
267
  }
253
268
  get el() { return getElement(this); }
254
269
  };