@zanichelli/zanichelli-it-frontend-kit 1.2.0 → 1.3.0-RC2

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.
Files changed (73) hide show
  1. package/dist/cjs/{index-q1XSBSqA.js → index-CRwLFnL1.js} +7 -3
  2. package/dist/cjs/index-CRwLFnL1.js.map +1 -0
  3. package/dist/cjs/loader.cjs.js +2 -2
  4. package/dist/cjs/zanichelli-it-frontend-kit.cjs.js +2 -2
  5. package/dist/cjs/zanit-menubar.zanit-mobile-menubar.zanit-search-form.entry.cjs.js.map +1 -1
  6. package/dist/cjs/zanit-menubar_3.cjs.entry.js +266 -22
  7. package/dist/cjs/zanit-menubar_3.cjs.entry.js.map +1 -1
  8. package/dist/collection/components/menubar/menubar.css +1 -0
  9. package/dist/collection/components/menubar/menubar.js +53 -2
  10. package/dist/collection/components/menubar/menubar.js.map +1 -1
  11. package/dist/collection/components/menubar/mobile-menubar/mobile-menubar.js +52 -1
  12. package/dist/collection/components/menubar/mobile-menubar/mobile-menubar.js.map +1 -1
  13. package/dist/collection/components/menubar/search-form/search-form.css +51 -0
  14. package/dist/collection/components/menubar/search-form/search-form.js +207 -22
  15. package/dist/collection/components/menubar/search-form/search-form.js.map +1 -1
  16. package/dist/collection/components/menubar/search-form/suggestions.js +84 -0
  17. package/dist/collection/components/menubar/search-form/suggestions.js.map +1 -0
  18. package/dist/collection/utils/subjects.api.js +25 -0
  19. package/dist/collection/utils/subjects.api.js.map +1 -0
  20. package/dist/collection/utils/utils.js +8 -0
  21. package/dist/collection/utils/utils.js.map +1 -1
  22. package/dist/components/index.js +5 -2
  23. package/dist/components/index.js.map +1 -1
  24. package/dist/components/p-Bk8_DaVU.js +375 -0
  25. package/dist/components/p-Bk8_DaVU.js.map +1 -0
  26. package/dist/components/{p-DCsoOA4v.js → p-Cs52y6qp.js} +12 -5
  27. package/dist/components/p-Cs52y6qp.js.map +1 -0
  28. package/dist/components/zanit-menubar.js +13 -6
  29. package/dist/components/zanit-menubar.js.map +1 -1
  30. package/dist/components/zanit-mobile-menubar.js +1 -1
  31. package/dist/components/zanit-search-form.js +1 -1
  32. package/dist/esm/{index-CaWL2omE.js → index-B82IapZZ.js} +7 -4
  33. package/dist/esm/index-B82IapZZ.js.map +1 -0
  34. package/dist/esm/loader.js +3 -3
  35. package/dist/esm/zanichelli-it-frontend-kit.js +3 -3
  36. package/dist/esm/zanit-menubar.zanit-mobile-menubar.zanit-search-form.entry.js.map +1 -1
  37. package/dist/esm/zanit-menubar_3.entry.js +266 -22
  38. package/dist/esm/zanit-menubar_3.entry.js.map +1 -1
  39. package/dist/types/components/menubar/menubar.d.ts +5 -0
  40. package/dist/types/components/menubar/mobile-menubar/mobile-menubar.d.ts +5 -0
  41. package/dist/types/components/menubar/search-form/search-form.d.ts +28 -5
  42. package/dist/types/components/menubar/search-form/suggestions.d.ts +11 -0
  43. package/dist/types/components.d.ts +60 -4
  44. package/dist/types/utils/subjects.api.d.ts +6 -0
  45. package/dist/types/utils/types.d.ts +7 -0
  46. package/dist/types/utils/utils.d.ts +8 -0
  47. package/dist/zanichelli-it-frontend-kit/p-1dddc763.entry.js +2 -0
  48. package/dist/zanichelli-it-frontend-kit/p-1dddc763.entry.js.map +1 -0
  49. package/{www/build/p-CaWL2omE.js → dist/zanichelli-it-frontend-kit/p-B82IapZZ.js} +2 -2
  50. package/dist/zanichelli-it-frontend-kit/p-B82IapZZ.js.map +1 -0
  51. package/dist/zanichelli-it-frontend-kit/zanichelli-it-frontend-kit.esm.js +1 -1
  52. package/dist/zanichelli-it-frontend-kit/zanit-menubar.zanit-mobile-menubar.zanit-search-form.entry.esm.js.map +1 -1
  53. package/package.json +11 -12
  54. package/www/build/p-1dddc763.entry.js +2 -0
  55. package/www/build/p-1dddc763.entry.js.map +1 -0
  56. package/{dist/zanichelli-it-frontend-kit/p-CaWL2omE.js → www/build/p-B82IapZZ.js} +2 -2
  57. package/www/build/p-B82IapZZ.js.map +1 -0
  58. package/www/build/p-d121e671.js +2 -0
  59. package/www/build/zanichelli-it-frontend-kit.esm.js +1 -1
  60. package/www/build/zanit-menubar.zanit-mobile-menubar.zanit-search-form.entry.esm.js.map +1 -1
  61. package/www/index.html +5 -1
  62. package/dist/cjs/index-q1XSBSqA.js.map +0 -1
  63. package/dist/components/p-C_SXGfG9.js +0 -133
  64. package/dist/components/p-C_SXGfG9.js.map +0 -1
  65. package/dist/components/p-DCsoOA4v.js.map +0 -1
  66. package/dist/esm/index-CaWL2omE.js.map +0 -1
  67. package/dist/zanichelli-it-frontend-kit/p-217f87ff.entry.js +0 -2
  68. package/dist/zanichelli-it-frontend-kit/p-217f87ff.entry.js.map +0 -1
  69. package/dist/zanichelli-it-frontend-kit/p-CaWL2omE.js.map +0 -1
  70. package/www/build/p-1d74b708.js +0 -2
  71. package/www/build/p-217f87ff.entry.js +0 -2
  72. package/www/build/p-217f87ff.entry.js.map +0 -1
  73. package/www/build/p-CaWL2omE.js.map +0 -1
@@ -1,45 +1,80 @@
1
- import { h } from "@stencil/core";
2
- import { containsTarget } from "../../../utils";
1
+ import { h, Host } from "@stencil/core";
2
+ import { containsTarget, isArrowDownKey, isArrowUpKey, isEscKey, isTabKey } from "../../../utils";
3
+ import { getSubjectsByArea, SearchEnv } from "../../../utils/subjects.api";
4
+ import { buildSuggestions } from "./suggestions";
3
5
  export class ZanitSearchForm {
4
6
  formElement;
7
+ subjectsByArea = {};
8
+ timer;
5
9
  host;
6
10
  /** Indicates whether the searchbar is visible and usable. */
7
11
  showSearchbar = false;
8
12
  /** Search query to apply. */
9
13
  _searchQuery = undefined;
14
+ /** Search suggestions to show in the autocomplete dropdown. */
15
+ suggestions = [];
16
+ /** Active suggestion - used for keyboard navigation */
17
+ activeSuggestion = '';
18
+ /** Show suggestions list */
19
+ showSuggestions = false;
10
20
  /** Initial search query */
11
21
  searchQuery = undefined;
22
+ /** Environment for search suggestions */
23
+ searchEnv = SearchEnv.PROD;
24
+ /** Search area (e.g. "SCUOLA", "UNIVERSITÀ", "DIZIONARI"). */
25
+ searchArea;
12
26
  onSearchQueryChange() {
13
27
  this._searchQuery = this.searchQuery;
14
28
  if (this.searchQuery) {
15
29
  this.openSearchbar();
16
30
  }
31
+ this.resetSuggestions();
32
+ }
33
+ onSearchAreaChange() {
34
+ this.resetSuggestions();
35
+ }
36
+ onShowSearchbarChange() {
37
+ if (!this.showSearchbar) {
38
+ this.showSuggestions = false;
39
+ }
40
+ }
41
+ onShowSuggestionsChange() {
42
+ this.activeSuggestion = '';
17
43
  }
18
44
  /** Emitted on search form submission. */
19
45
  search;
20
46
  resetSearch;
21
47
  async connectedCallback() {
48
+ this.subjectsByArea = await getSubjectsByArea(this.searchEnv);
22
49
  this.showSearchbar = !!this.searchQuery;
23
50
  this._searchQuery = this.searchQuery;
24
51
  }
25
52
  /** Close open searchbar when clicking outside. */
26
53
  handleOutsideClick(event) {
27
- if (this.showSearchbar && this.formElement && !containsTarget(this.formElement, event)) {
54
+ if (this.showSearchbar && this.host && !containsTarget(this.host, event)) {
28
55
  this.showSearchbar = false;
29
56
  }
30
57
  }
31
- /** Close the menu when pressing Escape or Tab. */
32
- handleKeydown(event) {
33
- switch (event.key) {
34
- case 'Escape':
35
- this.showSearchbar = false;
36
- break;
37
- case 'Tab':
38
- if (containsTarget(this.host, event)) {
39
- break;
40
- }
41
- this.showSearchbar = false;
42
- break;
58
+ /** Close the searchbar/suggestions when pressing Escape. */
59
+ handleEsc(event) {
60
+ if (!isEscKey(event)) {
61
+ return;
62
+ }
63
+ if (this.showSuggestions) {
64
+ this.showSuggestions = false;
65
+ }
66
+ else {
67
+ this.showSearchbar = false;
68
+ }
69
+ }
70
+ /** Close the searchbar/suggestions when pressing Tab. */
71
+ handleTab(event) {
72
+ if (!isTabKey(event)) {
73
+ return;
74
+ }
75
+ this.showSuggestions = false;
76
+ if (!containsTarget(this.host, event)) {
77
+ this.showSearchbar = false;
43
78
  }
44
79
  }
45
80
  openSearchbar() {
@@ -53,27 +88,108 @@ export class ZanitSearchForm {
53
88
  this.searchQuery = undefined;
54
89
  this.resetSearch.emit();
55
90
  }
91
+ resetSuggestions() {
92
+ this.suggestions = [];
93
+ this.showSuggestions = false;
94
+ }
56
95
  handleInputChange(event) {
57
96
  this._searchQuery = event.target.value;
58
97
  if (!this._searchQuery) {
59
98
  this.searchQuery = undefined;
60
99
  }
100
+ this.updateSuggestions();
101
+ }
102
+ updateSuggestions() {
103
+ clearTimeout(this.timer);
104
+ const query = (this._searchQuery || '').trim();
105
+ if (query.length < 3) {
106
+ this.resetSuggestions();
107
+ return;
108
+ }
109
+ this.timer = setTimeout(() => {
110
+ this.resetSuggestions();
111
+ this.suggestions = buildSuggestions(query, this.subjectsByArea, this.searchArea?.toUpperCase());
112
+ this.showSuggestions = true;
113
+ }, 300);
61
114
  }
62
115
  onSearchSubmit(event) {
63
116
  event.preventDefault();
64
117
  if (!this._searchQuery) {
65
118
  return;
66
119
  }
120
+ if (this.activeSuggestion) {
121
+ const suggestion = this.suggestions.find((s) => s.id === this.activeSuggestion);
122
+ if (suggestion) {
123
+ this.submitSuggestionSearch(suggestion);
124
+ this.showSuggestions = false;
125
+ return;
126
+ }
127
+ }
67
128
  this.showSearchbar = false;
68
- const searchEv = this.search.emit({ query: this._searchQuery });
129
+ const searchEv = this.search.emit({ query: this._searchQuery, area: this.searchArea });
69
130
  // do not submit the form if the event default behavior was prevented
70
131
  if (searchEv.defaultPrevented) {
71
132
  return;
72
133
  }
73
134
  this.formElement.submit();
74
135
  }
136
+ submitSuggestionSearch(suggestion) {
137
+ const ev = this.search.emit({
138
+ user_query: suggestion.user_query,
139
+ query: suggestion.query,
140
+ area: suggestion.area,
141
+ subject: suggestion.subject,
142
+ });
143
+ if (!ev.defaultPrevented) {
144
+ window.location.href = suggestion.url;
145
+ }
146
+ }
147
+ handleSuggestionsNav(event) {
148
+ if (!isArrowDownKey(event) && !isArrowUpKey(event)) {
149
+ return;
150
+ }
151
+ if (!this.suggestions.length) {
152
+ return;
153
+ }
154
+ const options = this.suggestions.map((o) => o.id);
155
+ if (!options.length) {
156
+ return;
157
+ }
158
+ event.preventDefault();
159
+ event.stopPropagation();
160
+ if (!this.showSuggestions) {
161
+ this.showSuggestions = true;
162
+ }
163
+ let nextId = null;
164
+ const firstId = options[0];
165
+ const lastId = options[options.length - 1];
166
+ const currOption = options.indexOf(this.activeSuggestion);
167
+ if (currOption < 0) {
168
+ nextId = isArrowDownKey(event) ? firstId : lastId;
169
+ }
170
+ else {
171
+ if (isArrowDownKey(event)) {
172
+ nextId = options[currOption + 1] || lastId;
173
+ }
174
+ else {
175
+ nextId = options[currOption - 1] || firstId;
176
+ }
177
+ }
178
+ this.activeSuggestion = nextId;
179
+ }
180
+ renderSuggestions() {
181
+ return (h("div", { class: { 'suggestions-wrapper': true, 'hidden': !this.showSuggestions || !this.suggestions.length }, onPointerOver: (e) => e.preventDefault() }, h("div", { id: "search-suggestions", class: "suggestions", role: "listbox", "aria-label": "Seleziona tra i suggerimenti" }, this.suggestions.map((suggestion, k) => {
182
+ return (h("span", { key: k, innerHTML: suggestion.html_label, id: suggestion.id, class: "suggestion", role: "option", "aria-label": suggestion.label, "aria-selected": this.activeSuggestion === suggestion.id ? 'true' : undefined, onClick: () => this.submitSuggestionSearch(suggestion) }));
183
+ }))));
184
+ }
75
185
  render() {
76
- return (h("form", { key: 'fe6f284342dbd746e36d5cb3c5707dcce305c161', class: { 'searchbar': true, 'searchbar-open': this.showSearchbar }, ref: (el) => (this.formElement = el), role: "search", "aria-label": "Cerca nel sito", method: "get", action: "/ricerca", onSubmit: (event) => this.onSearchSubmit(event), onReset: () => this.resetSearchQuery() }, h("div", { key: '593b2cccc1d01244e4d9dbf5a1cc90cf1e9075f2', class: "input-wrapper", role: "none" }, this.searchQuery && (h("button", { key: 'f5ef76db0bb2c1a071a61d1284b5828b14be0a88', type: "reset", "aria-label": "Svuota campo di ricerca", disabled: !this.showSearchbar }, h("z-icon", { key: '05e87942a4e49aebbdf537acd61d9cddf5f3e094', name: "multiply-circled" }))), h("input", { key: '7dc3338831b3e038e4eeb145703380c7c68e3d30', id: "searchbar-input", name: "q", type: "search", disabled: !this.showSearchbar, placeholder: "Cerca per parola chiave o ISBN", onInput: (event) => this.handleInputChange(event), value: this.searchQuery, required: true })), h("button", { key: '8b3e4c3a9976fd72b2279e0af1dc5f8fbe80aab2', class: "searchbar-button", "aria-label": "Esegui ricerca", "aria-controls": "searchbar-input", type: this.showSearchbar ? 'submit' : 'button', onClick: () => this.openSearchbar() }, this.showSearchbar ? null : h("span", { class: "searchbar-button-label" }, "Cerca"), h("z-icon", { key: '10fb650b9447bb1ef8cee43e096e1e800d403b60', name: "search" }))));
186
+ return (h(Host, { key: '7ac06128ddbb7b5eed2d579d615607f725a3d922' }, h("form", { key: '238b35f0aa41c95b3329da5fc80e17f3a47dfff6', class: { 'searchbar': true, 'searchbar-open': this.showSearchbar }, ref: (el) => (this.formElement = el), role: "search", "aria-label": "Cerca nel sito", method: "get", action: "/ricerca", onSubmit: (event) => this.onSearchSubmit(event), onReset: () => this.resetSearchQuery() }, !!this.searchArea && (h("input", { key: 'bdd71f66a0947eeae7f657298cc2397f512884ab', type: "hidden", name: "area", value: this.searchArea })), h("div", { key: '9e40abc78a5d1910ace9bc628f10035696df7e7f', class: "input-wrapper", role: "none" }, this.searchQuery && (h("button", { key: 'f84706b7c06dabb0b6a81eae6530e26eddc95a04', type: "reset", "aria-label": "Svuota campo di ricerca", disabled: !this.showSearchbar, "aria-hidden": !this.showSearchbar ? 'true' : undefined, tabIndex: !this.showSearchbar ? -1 : 0 }, h("z-icon", { key: '6ff774cf791dc2f7ebb1861a5697e27ae040206f', name: "multiply-circled" }))), h("input", { key: 'e53291d60e203c72a79af09eb9072dde62b6a916', id: "searchbar-input", name: "q", type: "search", disabled: !this.showSearchbar, placeholder: "Cerca per parola chiave o ISBN", value: this.searchQuery, required: true, autocomplete: "off", role: "combobox", "aria-autocomplete": "list", "aria-expanded": this.showSuggestions ? 'true' : 'false', "aria-controls": "search-suggestions", "aria-activedescendant": this.activeSuggestion, "aria-label": "Cerca per parola chiave o ISBN", "aria-hidden": !this.showSearchbar ? 'true' : undefined, tabIndex: !this.showSearchbar ? -1 : 0, onInput: (event) => this.handleInputChange(event), onKeyDown: (e) => {
187
+ // INFO: prevent ESC from clearing input
188
+ if (isEscKey(e)) {
189
+ e.preventDefault();
190
+ }
191
+ this.handleSuggestionsNav(e);
192
+ } })), h("button", { key: '836604e75ca90d451cba93236509f20a3a22cf16', class: "searchbar-button", "aria-label": this.showSearchbar ? 'Esegui ricerca' : 'Apri il campo di ricerca', "aria-controls": "searchbar-input", type: this.showSearchbar ? 'submit' : 'button', onClick: () => this.openSearchbar() }, this.showSearchbar ? null : h("span", { class: "searchbar-button-label" }, "Cerca"), h("z-icon", { key: '1616128d97c04a1e4768f163fcc20a21664daca4', name: "search" }))), this.renderSuggestions()));
77
193
  }
78
194
  static get is() { return "zanit-search-form"; }
79
195
  static get encapsulation() { return "shadow"; }
@@ -108,13 +224,61 @@ export class ZanitSearchForm {
108
224
  "setter": false,
109
225
  "reflect": false,
110
226
  "defaultValue": "undefined"
227
+ },
228
+ "searchEnv": {
229
+ "type": "string",
230
+ "attribute": "search-env",
231
+ "mutable": false,
232
+ "complexType": {
233
+ "original": "SearchEnv",
234
+ "resolved": "SearchEnv.DEV | SearchEnv.PROD | SearchEnv.TEST",
235
+ "references": {
236
+ "SearchEnv": {
237
+ "location": "import",
238
+ "path": "../../../utils/subjects.api",
239
+ "id": "src/utils/subjects.api.ts::SearchEnv"
240
+ }
241
+ }
242
+ },
243
+ "required": false,
244
+ "optional": false,
245
+ "docs": {
246
+ "tags": [],
247
+ "text": "Environment for search suggestions"
248
+ },
249
+ "getter": false,
250
+ "setter": false,
251
+ "reflect": false,
252
+ "defaultValue": "SearchEnv.PROD"
253
+ },
254
+ "searchArea": {
255
+ "type": "string",
256
+ "attribute": "search-area",
257
+ "mutable": false,
258
+ "complexType": {
259
+ "original": "string | undefined",
260
+ "resolved": "string",
261
+ "references": {}
262
+ },
263
+ "required": false,
264
+ "optional": true,
265
+ "docs": {
266
+ "tags": [],
267
+ "text": "Search area (e.g. \"SCUOLA\", \"UNIVERSIT\u00C0\", \"DIZIONARI\")."
268
+ },
269
+ "getter": false,
270
+ "setter": false,
271
+ "reflect": false
111
272
  }
112
273
  };
113
274
  }
114
275
  static get states() {
115
276
  return {
116
277
  "showSearchbar": {},
117
- "_searchQuery": {}
278
+ "_searchQuery": {},
279
+ "suggestions": {},
280
+ "activeSuggestion": {},
281
+ "showSuggestions": {}
118
282
  };
119
283
  }
120
284
  static get events() {
@@ -129,9 +293,15 @@ export class ZanitSearchForm {
129
293
  "text": "Emitted on search form submission."
130
294
  },
131
295
  "complexType": {
132
- "original": "{ query: string }",
133
- "resolved": "{ query: string; }",
134
- "references": {}
296
+ "original": "SearchEvent",
297
+ "resolved": "{ query?: string; area?: string; subject?: string; user_query?: string; }",
298
+ "references": {
299
+ "SearchEvent": {
300
+ "location": "import",
301
+ "path": "../../../utils",
302
+ "id": "src/utils/index.ts::SearchEvent"
303
+ }
304
+ }
135
305
  }
136
306
  }, {
137
307
  "method": "resetSearch",
@@ -155,6 +325,15 @@ export class ZanitSearchForm {
155
325
  return [{
156
326
  "propName": "searchQuery",
157
327
  "methodName": "onSearchQueryChange"
328
+ }, {
329
+ "propName": "searchArea",
330
+ "methodName": "onSearchAreaChange"
331
+ }, {
332
+ "propName": "showSearchbar",
333
+ "methodName": "onShowSearchbarChange"
334
+ }, {
335
+ "propName": "showSuggestions",
336
+ "methodName": "onShowSuggestionsChange"
158
337
  }];
159
338
  }
160
339
  static get listeners() {
@@ -166,10 +345,16 @@ export class ZanitSearchForm {
166
345
  "passive": true
167
346
  }, {
168
347
  "name": "keydown",
169
- "method": "handleKeydown",
348
+ "method": "handleEsc",
170
349
  "target": undefined,
171
350
  "capture": false,
172
351
  "passive": true
352
+ }, {
353
+ "name": "keyup",
354
+ "method": "handleTab",
355
+ "target": "document",
356
+ "capture": false,
357
+ "passive": true
173
358
  }];
174
359
  }
175
360
  }
@@ -1 +1 @@
1
- {"version":3,"file":"search-form.js","sourceRoot":"","sources":["../../../../src/components/menubar/search-form/search-form.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, Element, Event, EventEmitter, h, Listen, Prop, State, Watch } from '@stencil/core';\nimport { containsTarget } from '../../../utils';\n\n@Component({\n tag: 'zanit-search-form',\n styleUrl: 'search-form.css',\n shadow: true,\n})\nexport class ZanitSearchForm {\n private formElement: HTMLFormElement;\n\n @Element() host: HTMLZanitSearchFormElement;\n\n /** Indicates whether the searchbar is visible and usable. */\n @State()\n showSearchbar: boolean = false;\n\n /** Search query to apply. */\n @State()\n _searchQuery: string | undefined = undefined;\n\n /** Initial search query */\n @Prop({ mutable: true })\n searchQuery: string | undefined = undefined;\n\n @Watch('searchQuery')\n onSearchQueryChange() {\n this._searchQuery = this.searchQuery;\n if (this.searchQuery) {\n this.openSearchbar();\n }\n }\n\n /** Emitted on search form submission. */\n @Event({ cancelable: true }) search: EventEmitter<{ query: string }>;\n\n @Event() resetSearch: EventEmitter<void>;\n\n async connectedCallback() {\n this.showSearchbar = !!this.searchQuery;\n this._searchQuery = this.searchQuery;\n }\n\n /** Close open searchbar when clicking outside. */\n @Listen('click', { target: 'document', passive: true })\n handleOutsideClick(event: MouseEvent) {\n if (this.showSearchbar && this.formElement && !containsTarget(this.formElement, event)) {\n this.showSearchbar = false;\n }\n }\n\n /** Close the menu when pressing Escape or Tab. */\n @Listen('keydown', { passive: true })\n handleKeydown(event: KeyboardEvent) {\n switch (event.key) {\n case 'Escape':\n this.showSearchbar = false;\n break;\n case 'Tab':\n if (containsTarget(this.host, event)) {\n break;\n }\n\n this.showSearchbar = false;\n break;\n }\n }\n\n private openSearchbar() {\n this.showSearchbar = true;\n setTimeout(() => {\n const searchbarInput = this.host.shadowRoot.querySelector('#searchbar-input') as HTMLInputElement;\n searchbarInput.focus({ preventScroll: true });\n }, 500);\n }\n\n private resetSearchQuery() {\n this.searchQuery = undefined;\n this.resetSearch.emit();\n }\n\n private handleInputChange(event: Event) {\n this._searchQuery = (event.target as HTMLInputElement).value;\n if (!this._searchQuery) {\n this.searchQuery = undefined;\n }\n }\n\n private onSearchSubmit(event: Event) {\n event.preventDefault();\n if (!this._searchQuery) {\n return;\n }\n\n this.showSearchbar = false;\n const searchEv = this.search.emit({ query: this._searchQuery });\n // do not submit the form if the event default behavior was prevented\n if (searchEv.defaultPrevented) {\n return;\n }\n\n this.formElement.submit();\n }\n\n render() {\n return (\n <form\n class={{ 'searchbar': true, 'searchbar-open': this.showSearchbar }}\n ref={(el) => (this.formElement = el)}\n role=\"search\"\n aria-label=\"Cerca nel sito\"\n method=\"get\"\n action=\"/ricerca\"\n onSubmit={(event) => this.onSearchSubmit(event)}\n onReset={() => this.resetSearchQuery()}\n >\n <div\n class=\"input-wrapper\"\n role=\"none\"\n >\n {this.searchQuery && (\n <button\n type=\"reset\"\n aria-label=\"Svuota campo di ricerca\"\n disabled={!this.showSearchbar}\n >\n <z-icon name=\"multiply-circled\" />\n </button>\n )}\n <input\n id=\"searchbar-input\"\n name=\"q\"\n type=\"search\"\n disabled={!this.showSearchbar}\n placeholder=\"Cerca per parola chiave o ISBN\"\n onInput={(event) => this.handleInputChange(event)}\n value={this.searchQuery}\n required\n ></input>\n </div>\n\n <button\n class=\"searchbar-button\"\n aria-label=\"Esegui ricerca\"\n aria-controls=\"searchbar-input\"\n type={this.showSearchbar ? 'submit' : 'button'}\n onClick={() => this.openSearchbar()}\n >\n {this.showSearchbar ? null : <span class=\"searchbar-button-label\">Cerca</span>}\n <z-icon name=\"search\"></z-icon>\n </button>\n </form>\n );\n }\n}\n"]}
1
+ {"version":3,"file":"search-form.js","sourceRoot":"","sources":["../../../../src/components/menubar/search-form/search-form.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, Element, Event, EventEmitter, h, Host, Listen, Prop, State, Watch } from '@stencil/core';\nimport { containsTarget, isArrowDownKey, isArrowUpKey, isEscKey, isTabKey, SearchEvent } from '../../../utils';\nimport { getSubjectsByArea, SearchEnv } from '../../../utils/subjects.api';\nimport { buildSuggestions, SearchSuggestion } from './suggestions';\n\n@Component({\n tag: 'zanit-search-form',\n styleUrl: 'search-form.css',\n shadow: true,\n})\nexport class ZanitSearchForm {\n private formElement: HTMLFormElement;\n private subjectsByArea: Record<string, string[]> = {};\n private timer: NodeJS.Timeout;\n\n @Element() host: HTMLZanitSearchFormElement;\n\n /** Indicates whether the searchbar is visible and usable. */\n @State()\n showSearchbar: boolean = false;\n\n /** Search query to apply. */\n @State()\n _searchQuery: string | undefined = undefined;\n\n /** Search suggestions to show in the autocomplete dropdown. */\n @State() suggestions: SearchSuggestion[] = [];\n\n /** Active suggestion - used for keyboard navigation */\n @State() activeSuggestion: string = '';\n\n /** Show suggestions list */\n @State() showSuggestions: boolean = false;\n\n /** Initial search query */\n @Prop({ mutable: true })\n searchQuery: string | undefined = undefined;\n\n /** Environment for search suggestions */\n @Prop() searchEnv: SearchEnv = SearchEnv.PROD;\n\n /** Search area (e.g. \"SCUOLA\", \"UNIVERSITÀ\", \"DIZIONARI\"). */\n @Prop() searchArea?: string | undefined;\n\n @Watch('searchQuery')\n onSearchQueryChange() {\n this._searchQuery = this.searchQuery;\n if (this.searchQuery) {\n this.openSearchbar();\n }\n this.resetSuggestions();\n }\n\n @Watch('searchArea')\n onSearchAreaChange() {\n this.resetSuggestions();\n }\n\n @Watch('showSearchbar')\n onShowSearchbarChange() {\n if (!this.showSearchbar) {\n this.showSuggestions = false;\n }\n }\n\n @Watch('showSuggestions')\n onShowSuggestionsChange() {\n this.activeSuggestion = '';\n }\n\n /** Emitted on search form submission. */\n @Event({ cancelable: true }) search: EventEmitter<SearchEvent>;\n\n @Event() resetSearch: EventEmitter<void>;\n\n async connectedCallback() {\n this.subjectsByArea = await getSubjectsByArea(this.searchEnv);\n this.showSearchbar = !!this.searchQuery;\n this._searchQuery = this.searchQuery;\n }\n\n /** Close open searchbar when clicking outside. */\n @Listen('click', { target: 'document', passive: true })\n handleOutsideClick(event: MouseEvent) {\n if (this.showSearchbar && this.host && !containsTarget(this.host, event)) {\n this.showSearchbar = false;\n }\n }\n\n /** Close the searchbar/suggestions when pressing Escape. */\n @Listen('keydown', { passive: true })\n handleEsc(event: KeyboardEvent) {\n if (!isEscKey(event)) {\n return;\n }\n\n if (this.showSuggestions) {\n this.showSuggestions = false;\n } else {\n this.showSearchbar = false;\n }\n }\n\n /** Close the searchbar/suggestions when pressing Tab. */\n @Listen('keyup', { target: 'document', passive: true })\n handleTab(event: KeyboardEvent) {\n if (!isTabKey(event)) {\n return;\n }\n\n this.showSuggestions = false;\n\n if (!containsTarget(this.host, event)) {\n this.showSearchbar = false;\n }\n }\n\n private openSearchbar() {\n this.showSearchbar = true;\n setTimeout(() => {\n const searchbarInput = this.host.shadowRoot.querySelector('#searchbar-input') as HTMLInputElement;\n searchbarInput.focus({ preventScroll: true });\n }, 500);\n }\n\n private resetSearchQuery() {\n this.searchQuery = undefined;\n this.resetSearch.emit();\n }\n\n private resetSuggestions() {\n this.suggestions = [];\n this.showSuggestions = false;\n }\n\n private handleInputChange(event: InputEvent) {\n this._searchQuery = (event.target as HTMLInputElement).value;\n if (!this._searchQuery) {\n this.searchQuery = undefined;\n }\n\n this.updateSuggestions();\n }\n\n private updateSuggestions() {\n clearTimeout(this.timer);\n\n const query = (this._searchQuery || '').trim();\n\n if (query.length < 3) {\n this.resetSuggestions();\n return;\n }\n\n this.timer = setTimeout(() => {\n this.resetSuggestions();\n this.suggestions = buildSuggestions(query, this.subjectsByArea, this.searchArea?.toUpperCase());\n this.showSuggestions = true;\n }, 300);\n }\n\n private onSearchSubmit(event: Event) {\n event.preventDefault();\n if (!this._searchQuery) {\n return;\n }\n\n if (this.activeSuggestion) {\n const suggestion = this.suggestions.find((s) => s.id === this.activeSuggestion);\n if (suggestion) {\n this.submitSuggestionSearch(suggestion);\n this.showSuggestions = false;\n return;\n }\n }\n\n this.showSearchbar = false;\n\n const searchEv = this.search.emit({ query: this._searchQuery, area: this.searchArea });\n // do not submit the form if the event default behavior was prevented\n if (searchEv.defaultPrevented) {\n return;\n }\n\n this.formElement.submit();\n }\n\n private submitSuggestionSearch(suggestion: SearchSuggestion) {\n const ev = this.search.emit({\n user_query: suggestion.user_query,\n query: suggestion.query,\n area: suggestion.area,\n subject: suggestion.subject,\n });\n if (!ev.defaultPrevented) {\n window.location.href = suggestion.url;\n }\n }\n\n private handleSuggestionsNav(event: KeyboardEvent) {\n if (!isArrowDownKey(event) && !isArrowUpKey(event)) {\n return;\n }\n\n if (!this.suggestions.length) {\n return;\n }\n\n const options = this.suggestions.map((o) => o.id);\n\n if (!options.length) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n if (!this.showSuggestions) {\n this.showSuggestions = true;\n }\n\n let nextId = null;\n const firstId = options[0];\n const lastId = options[options.length - 1];\n const currOption = options.indexOf(this.activeSuggestion);\n if (currOption < 0) {\n nextId = isArrowDownKey(event) ? firstId : lastId;\n } else {\n if (isArrowDownKey(event)) {\n nextId = options[currOption + 1] || lastId;\n } else {\n nextId = options[currOption - 1] || firstId;\n }\n }\n this.activeSuggestion = nextId;\n }\n\n private renderSuggestions() {\n return (\n <div\n class={{ 'suggestions-wrapper': true, 'hidden': !this.showSuggestions || !this.suggestions.length }}\n onPointerOver={(e) => e.preventDefault()}\n >\n <div\n id=\"search-suggestions\"\n class=\"suggestions\"\n role=\"listbox\"\n aria-label=\"Seleziona tra i suggerimenti\"\n >\n {this.suggestions.map((suggestion, k) => {\n return (\n <span\n key={k}\n innerHTML={suggestion.html_label}\n id={suggestion.id}\n class=\"suggestion\"\n role=\"option\"\n aria-label={suggestion.label}\n aria-selected={this.activeSuggestion === suggestion.id ? 'true' : undefined}\n onClick={() => this.submitSuggestionSearch(suggestion)}\n />\n );\n })}\n </div>\n </div>\n );\n }\n\n render() {\n return (\n <Host>\n <form\n class={{ 'searchbar': true, 'searchbar-open': this.showSearchbar }}\n ref={(el) => (this.formElement = el)}\n role=\"search\"\n aria-label=\"Cerca nel sito\"\n method=\"get\"\n action=\"/ricerca\"\n onSubmit={(event) => this.onSearchSubmit(event)}\n onReset={() => this.resetSearchQuery()}\n >\n {!!this.searchArea && (\n <input\n type=\"hidden\"\n name=\"area\"\n value={this.searchArea}\n />\n )}\n\n <div\n class=\"input-wrapper\"\n role=\"none\"\n >\n {this.searchQuery && (\n <button\n type=\"reset\"\n aria-label=\"Svuota campo di ricerca\"\n disabled={!this.showSearchbar}\n aria-hidden={!this.showSearchbar ? 'true' : undefined}\n tabIndex={!this.showSearchbar ? -1 : 0}\n >\n <z-icon name=\"multiply-circled\" />\n </button>\n )}\n <input\n id=\"searchbar-input\"\n name=\"q\"\n type=\"search\"\n disabled={!this.showSearchbar}\n placeholder=\"Cerca per parola chiave o ISBN\"\n value={this.searchQuery}\n required\n autocomplete=\"off\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={this.showSuggestions ? 'true' : 'false'}\n aria-controls=\"search-suggestions\"\n aria-activedescendant={this.activeSuggestion}\n aria-label=\"Cerca per parola chiave o ISBN\"\n aria-hidden={!this.showSearchbar ? 'true' : undefined}\n tabIndex={!this.showSearchbar ? -1 : 0}\n onInput={(event) => this.handleInputChange(event)}\n onKeyDown={(e) => {\n // INFO: prevent ESC from clearing input\n if (isEscKey(e)) {\n e.preventDefault();\n }\n\n this.handleSuggestionsNav(e);\n }}\n />\n </div>\n\n <button\n class=\"searchbar-button\"\n aria-label={this.showSearchbar ? 'Esegui ricerca' : 'Apri il campo di ricerca'}\n aria-controls=\"searchbar-input\"\n type={this.showSearchbar ? 'submit' : 'button'}\n onClick={() => this.openSearchbar()}\n >\n {this.showSearchbar ? null : <span class=\"searchbar-button-label\">Cerca</span>}\n <z-icon name=\"search\"></z-icon>\n </button>\n </form>\n\n {this.renderSuggestions()}\n </Host>\n );\n }\n}\n"]}
@@ -0,0 +1,84 @@
1
+ var AREA_LABELS;
2
+ (function (AREA_LABELS) {
3
+ AREA_LABELS["SCUOLA"] = "Scuola";
4
+ AREA_LABELS["UNIVERSIT\u00C0"] = "Universit\u00E0";
5
+ AREA_LABELS["GIURIDICO"] = "Giuridico";
6
+ AREA_LABELS["DIZIONARI"] = "Dizionari";
7
+ AREA_LABELS["SAGGISTICA"] = "Saggistica";
8
+ })(AREA_LABELS || (AREA_LABELS = {}));
9
+ const AREA_ORDER = Object.keys(AREA_LABELS);
10
+ export function buildSuggestions(query, subjectsByArea, selectedArea) {
11
+ const matchingSubjectAreas = findSubjectAreas(query, subjectsByArea);
12
+ const hasSubject = matchingSubjectAreas.length > 0;
13
+ const subject = hasSubject ? query.toUpperCase() : undefined;
14
+ const suggestions = [];
15
+ if (selectedArea)
16
+ suggestions.push(buildWordSuggestion(query, selectedArea));
17
+ suggestions.push(buildWordSuggestion(query));
18
+ if (hasSubject) {
19
+ if (selectedArea) {
20
+ const orderedSubjectAreas = [
21
+ ...matchingSubjectAreas.filter((area) => area === selectedArea),
22
+ ...matchingSubjectAreas
23
+ .filter((area) => area !== selectedArea)
24
+ .sort((a, b) => getAreaOrder(a) - getAreaOrder(b)),
25
+ ];
26
+ orderedSubjectAreas.forEach((area) => suggestions.push(buildSubjectSuggestion(query, area, subject)));
27
+ }
28
+ else {
29
+ matchingSubjectAreas
30
+ .sort((a, b) => getAreaOrder(a) - getAreaOrder(b))
31
+ .forEach((subjectArea) => suggestions.push(buildSubjectSuggestion(query, subjectArea, subject)));
32
+ }
33
+ }
34
+ return suggestions;
35
+ }
36
+ const buildWordSuggestion = (user_query, area) => {
37
+ return {
38
+ id: buildId(`word-${user_query}-${area}`),
39
+ label: buildLabel(user_query, area, false, false),
40
+ html_label: buildLabel(user_query, area, false, true),
41
+ url: buildUrl({ q: user_query, ...(area ? { area } : {}), user_query }),
42
+ ...buildDetail(user_query, user_query, area),
43
+ };
44
+ };
45
+ const buildSubjectSuggestion = (user_query, area, subject) => {
46
+ return {
47
+ id: buildId(`subj-${user_query}-${area}-${subject}`),
48
+ label: buildLabel(user_query, area, true, false),
49
+ html_label: buildLabel(user_query, area, true, true),
50
+ url: buildUrl({ area, materia: subject, user_query }),
51
+ ...buildDetail(user_query, undefined, area, subject),
52
+ };
53
+ };
54
+ const buildId = (string) => string
55
+ .split('')
56
+ .map((c) => c.charCodeAt(0).toString(16))
57
+ .join('');
58
+ const buildUrl = (params) => {
59
+ return `ricerca?${new URLSearchParams(params).toString()}`;
60
+ };
61
+ const buildDetail = (user_query, query, area, subject) => ({
62
+ user_query,
63
+ ...(query ? { query } : {}),
64
+ ...(area ? { area } : {}),
65
+ ...(subject ? { subject } : {}),
66
+ });
67
+ const buildLabel = (user_query, area, isSubject = false, isHtml = false) => {
68
+ const openStrong = isHtml ? `<strong>` : ``;
69
+ const closeStrong = isHtml ? `</strong>` : ``;
70
+ return `Cerca la ${isSubject ? `materia` : `parola`} ${openStrong}${user_query}${closeStrong} ${area ? `nel catalogo ${openStrong}${AREA_LABELS[area] ?? area}${closeStrong}` : `in tutto il sito`}`;
71
+ };
72
+ function findSubjectAreas(query, subjectsByArea) {
73
+ const cleanedQuery = cleanSearch(query);
74
+ return Object.entries(subjectsByArea)
75
+ .filter(([, subjects]) => subjects.some((subject) => subject.toLowerCase() === cleanedQuery))
76
+ .map(([area]) => area);
77
+ }
78
+ /** Clear search string: lowercase, remove multiple spaces */
79
+ const cleanSearch = (s) => s.toLowerCase().replace(/\s+/g, ' ');
80
+ const getAreaOrder = (area) => {
81
+ const index = AREA_ORDER.indexOf(area);
82
+ return index >= 0 ? index : 100;
83
+ };
84
+ //# sourceMappingURL=suggestions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggestions.js","sourceRoot":"","sources":["../../../../src/components/menubar/search-form/suggestions.ts"],"names":[],"mappings":"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","sourcesContent":["enum AREA_LABELS {\n SCUOLA = 'Scuola',\n UNIVERSITÀ = 'Università',\n GIURIDICO = 'Giuridico',\n DIZIONARI = 'Dizionari',\n SAGGISTICA = 'Saggistica',\n}\n\nconst AREA_ORDER = Object.keys(AREA_LABELS);\n\nexport type SearchSuggestion = {\n id: string;\n label: string;\n html_label: string;\n url: string;\n user_query: string;\n query?: string;\n area?: string;\n subject?: string;\n};\n\nexport function buildSuggestions(\n query: string,\n subjectsByArea: Record<string, string[]>,\n selectedArea?: string\n): SearchSuggestion[] {\n const matchingSubjectAreas = findSubjectAreas(query, subjectsByArea);\n const hasSubject = matchingSubjectAreas.length > 0;\n const subject = hasSubject ? query.toUpperCase() : undefined;\n\n const suggestions: SearchSuggestion[] = [];\n\n if (selectedArea) suggestions.push(buildWordSuggestion(query, selectedArea));\n\n suggestions.push(buildWordSuggestion(query));\n\n if (hasSubject) {\n if (selectedArea) {\n const orderedSubjectAreas = [\n ...matchingSubjectAreas.filter((area) => area === selectedArea),\n ...matchingSubjectAreas\n .filter((area) => area !== selectedArea)\n .sort((a, b) => getAreaOrder(a) - getAreaOrder(b)),\n ];\n orderedSubjectAreas.forEach((area) => suggestions.push(buildSubjectSuggestion(query, area, subject)));\n } else {\n matchingSubjectAreas\n .sort((a, b) => getAreaOrder(a) - getAreaOrder(b))\n .forEach((subjectArea) => suggestions.push(buildSubjectSuggestion(query, subjectArea, subject)));\n }\n }\n\n return suggestions;\n}\n\nconst buildWordSuggestion = (user_query: string, area?: string): SearchSuggestion => {\n return {\n id: buildId(`word-${user_query}-${area}`),\n label: buildLabel(user_query, area, false, false),\n html_label: buildLabel(user_query, area, false, true),\n url: buildUrl({ q: user_query, ...(area ? { area } : {}), user_query }),\n ...buildDetail(user_query, user_query, area),\n };\n};\n\nconst buildSubjectSuggestion = (user_query: string, area: string, subject: string): SearchSuggestion => {\n return {\n id: buildId(`subj-${user_query}-${area}-${subject}`),\n label: buildLabel(user_query, area, true, false),\n html_label: buildLabel(user_query, area, true, true),\n url: buildUrl({ area, materia: subject, user_query }),\n ...buildDetail(user_query, undefined, area, subject),\n };\n};\n\nconst buildId = (string: string) =>\n string\n .split('')\n .map((c) => c.charCodeAt(0).toString(16))\n .join('');\n\nconst buildUrl = (params: Record<string, string>): string => {\n return `ricerca?${new URLSearchParams(params).toString()}`;\n};\n\nconst buildDetail = (user_query: string, query?: string, area?: string, subject?: string) => ({\n user_query,\n ...(query ? { query } : {}),\n ...(area ? { area } : {}),\n ...(subject ? { subject } : {}),\n});\n\nconst buildLabel = (user_query: string, area?: string, isSubject: boolean = false, isHtml: boolean = false) => {\n const openStrong = isHtml ? `<strong>` : ``;\n const closeStrong = isHtml ? `</strong>` : ``;\n\n return `Cerca la ${isSubject ? `materia` : `parola`} ${openStrong}${user_query}${closeStrong} ${area ? `nel catalogo ${openStrong}${AREA_LABELS[area] ?? area}${closeStrong}` : `in tutto il sito`}`;\n};\n\nfunction findSubjectAreas(query: string, subjectsByArea: Record<string, string[]>): string[] {\n const cleanedQuery = cleanSearch(query);\n return Object.entries(subjectsByArea)\n .filter(([, subjects]) => subjects.some((subject) => subject.toLowerCase() === cleanedQuery))\n .map(([area]) => area);\n}\n\n/** Clear search string: lowercase, remove multiple spaces */\nconst cleanSearch = (s: string) => s.toLowerCase().replace(/\\s+/g, ' ');\n\nconst getAreaOrder = (area: string) => {\n const index = AREA_ORDER.indexOf(area);\n return index >= 0 ? index : 100;\n};\n"]}
@@ -0,0 +1,25 @@
1
+ export var SearchEnv;
2
+ (function (SearchEnv) {
3
+ SearchEnv["DEV"] = "dev";
4
+ SearchEnv["TEST"] = "test";
5
+ SearchEnv["PROD"] = "prod";
6
+ })(SearchEnv || (SearchEnv = {}));
7
+ const S3_SHOP_URL = {
8
+ dev: 'https://zanichelli-shop-dev.s3.eu-west-1.amazonaws.com',
9
+ test: 'https://zanichelli-shop-test.s3.eu-west-1.amazonaws.com',
10
+ prod: 'https://zanichelli-shop.s3.eu-west-1.amazonaws.com',
11
+ };
12
+ export async function getSubjectsByArea(searchEnv) {
13
+ try {
14
+ const response = await fetch(`${S3_SHOP_URL[searchEnv]}/categories.json`);
15
+ if (!response.ok) {
16
+ throw new Error(`HTTP ${response.status}`);
17
+ }
18
+ return await response.json();
19
+ }
20
+ catch (err) {
21
+ console.error('Error fetching subjects:', err);
22
+ return {};
23
+ }
24
+ }
25
+ //# sourceMappingURL=subjects.api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subjects.api.js","sourceRoot":"","sources":["../../src/utils/subjects.api.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,SAIX;AAJD,WAAY,SAAS;IACnB,wBAAW,CAAA;IACX,0BAAa,CAAA;IACb,0BAAa,CAAA;AACf,CAAC,EAJW,SAAS,KAAT,SAAS,QAIpB;AAED,MAAM,WAAW,GAA2B;IAC1C,GAAG,EAAE,wDAAwD;IAC7D,IAAI,EAAE,yDAAyD;IAC/D,IAAI,EAAE,oDAAoD;CAC3D,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAoB;IAC1D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,WAAW,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;QAC1E,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC;QAC/C,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC","sourcesContent":["export enum SearchEnv {\n DEV = 'dev',\n TEST = 'test',\n PROD = 'prod',\n}\n\nconst S3_SHOP_URL: Record<string, string> = {\n dev: 'https://zanichelli-shop-dev.s3.eu-west-1.amazonaws.com',\n test: 'https://zanichelli-shop-test.s3.eu-west-1.amazonaws.com',\n prod: 'https://zanichelli-shop.s3.eu-west-1.amazonaws.com',\n};\n\nexport async function getSubjectsByArea(searchEnv: SearchEnv): Promise<Record<string, string[]>> {\n try {\n const response = await fetch(`${S3_SHOP_URL[searchEnv]}/categories.json`);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n return await response.json();\n } catch (err) {\n console.error('Error fetching subjects:', err);\n return {};\n }\n}\n"]}
@@ -14,4 +14,12 @@ export const moveFocus = (current, next) => {
14
14
  next.tabIndex = 0;
15
15
  next.focus({ preventScroll: true });
16
16
  };
17
+ /** Check if event key is ArrowUp */
18
+ export const isArrowUpKey = (event) => event.key === 'ArrowUp';
19
+ /** Check if event key is ArrowDown */
20
+ export const isArrowDownKey = (event) => event.key === 'ArrowDown';
21
+ /** Check if event key is Tab */
22
+ export const isTabKey = (event) => event.key === 'Tab';
23
+ /** Check if event key is Escape */
24
+ export const isEscKey = (event) => event.key === 'Escape';
17
25
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAqB,EAAE,KAAY,EAAE,EAAE;IACpE,OAAO,KAAK;SACT,YAAY,EAAE;SACd,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC;SACvD,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAiB,CAAC,CAAC,CAAC;AACxD,CAAC,CAAC;AAEF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,OAAoB,EAAE,IAAiB,EAAE,EAAE;IACnE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IACtB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;IAClB,IAAI,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;AACtC,CAAC,CAAC","sourcesContent":["/**\n * Check if an element contains an event target by checking its composedPath.\n * Useful when an event target may come from a component's shadow DOM.\n */\nexport const containsTarget = (ancestor: HTMLElement, event: Event) => {\n return event\n .composedPath()\n .filter((el) => el !== document && el !== window.window)\n .some((el) => ancestor.contains(el as HTMLElement));\n};\n\n/** Move the focus to `next` element, set tabindex to 0 for `next` and -1 to `current`. */\nexport const moveFocus = (current: HTMLElement, next: HTMLElement) => {\n current.tabIndex = -1;\n next.tabIndex = 0;\n next.focus({ preventScroll: true });\n};\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAqB,EAAE,KAAY,EAAE,EAAE;IACpE,OAAO,KAAK;SACT,YAAY,EAAE;SACd,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC;SACvD,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAiB,CAAC,CAAC,CAAC;AACxD,CAAC,CAAC;AAEF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,OAAoB,EAAE,IAAiB,EAAE,EAAE;IACnE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IACtB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;IAClB,IAAI,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;AACtC,CAAC,CAAC;AAEF,oCAAoC;AACpC,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAoB,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC;AAE9E,sCAAsC;AACtC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAoB,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,WAAW,CAAC;AAElF,gCAAgC;AAChC,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAoB,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC;AAEtE,mCAAmC;AACnC,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAoB,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC","sourcesContent":["/**\n * Check if an element contains an event target by checking its composedPath.\n * Useful when an event target may come from a component's shadow DOM.\n */\nexport const containsTarget = (ancestor: HTMLElement, event: Event) => {\n return event\n .composedPath()\n .filter((el) => el !== document && el !== window.window)\n .some((el) => ancestor.contains(el as HTMLElement));\n};\n\n/** Move the focus to `next` element, set tabindex to 0 for `next` and -1 to `current`. */\nexport const moveFocus = (current: HTMLElement, next: HTMLElement) => {\n current.tabIndex = -1;\n next.tabIndex = 0;\n next.focus({ preventScroll: true });\n};\n\n/** Check if event key is ArrowUp */\nexport const isArrowUpKey = (event: KeyboardEvent) => event.key === 'ArrowUp';\n\n/** Check if event key is ArrowDown */\nexport const isArrowDownKey = (event: KeyboardEvent) => event.key === 'ArrowDown';\n\n/** Check if event key is Tab */\nexport const isTabKey = (event: KeyboardEvent) => event.key === 'Tab';\n\n/** Check if event key is Escape */\nexport const isEscKey = (event: KeyboardEvent) => event.key === 'Escape';\n"]}
@@ -214,7 +214,10 @@ var unwrapErr = (result) => {
214
214
  }
215
215
  };
216
216
  function createShadowRoot(cmpMeta) {
217
- const shadowRoot = this.attachShadow({ mode: "open" });
217
+ const shadowRoot = this.attachShadow({
218
+ mode: "open",
219
+ delegatesFocus: !!(cmpMeta.$flags$ & 16 /* shadowDelegatesFocus */)
220
+ }) ;
218
221
  if (supportsConstructableStylesheets) {
219
222
  const sheet = new CSSStyleSheet();
220
223
  sheet.replaceSync(globalStyles);
@@ -1284,7 +1287,7 @@ function render(vnode, container) {
1284
1287
  renderVdom(ref, vnode);
1285
1288
  }
1286
1289
 
1287
- export { Fragment as F, H, createEvent as c, getAssetPath, h, proxyCustomElement as p, render, setAssetPath, setNonce, setPlatformOptions };
1290
+ export { Fragment as F, H, Host as a, createEvent as c, getAssetPath, h, proxyCustomElement as p, render, setAssetPath, setNonce, setPlatformOptions };
1288
1291
  //# sourceMappingURL=index.js.map
1289
1292
 
1290
1293
  //# sourceMappingURL=index.js.map