@zanichelli/zanichelli-it-frontend-kit 1.1.2-RC → 1.3.0-RC1

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 +267 -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 +45 -0
  14. package/dist/collection/components/menubar/search-form/search-form.js +208 -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-DCsoOA4v.js → p-CuXV3NdC.js} +12 -5
  25. package/dist/components/p-CuXV3NdC.js.map +1 -0
  26. package/dist/components/p-DRtCn2AS.js +376 -0
  27. package/dist/components/p-DRtCn2AS.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 +267 -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/{www/build/p-CaWL2omE.js → dist/zanichelli-it-frontend-kit/p-B82IapZZ.js} +2 -2
  48. package/dist/zanichelli-it-frontend-kit/p-B82IapZZ.js.map +1 -0
  49. package/dist/zanichelli-it-frontend-kit/p-d7e08556.entry.js +2 -0
  50. package/dist/zanichelli-it-frontend-kit/p-d7e08556.entry.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-3c83769f.js +2 -0
  55. package/{dist/zanichelli-it-frontend-kit/p-CaWL2omE.js → www/build/p-B82IapZZ.js} +2 -2
  56. package/www/build/p-B82IapZZ.js.map +1 -0
  57. package/www/build/p-d7e08556.entry.js +2 -0
  58. package/www/build/p-d7e08556.entry.js.map +1 -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 +1 -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,109 @@ 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
+ this.showSuggestions = false;
130
+ const searchEv = this.search.emit({ query: this._searchQuery, area: this.searchArea });
69
131
  // do not submit the form if the event default behavior was prevented
70
132
  if (searchEv.defaultPrevented) {
71
133
  return;
72
134
  }
73
135
  this.formElement.submit();
74
136
  }
137
+ submitSuggestionSearch(suggestion) {
138
+ const ev = this.search.emit({
139
+ user_query: suggestion.user_query,
140
+ query: suggestion.query,
141
+ area: suggestion.area,
142
+ subject: suggestion.subject,
143
+ });
144
+ if (!ev.defaultPrevented) {
145
+ window.location.href = suggestion.url;
146
+ }
147
+ }
148
+ handleSuggestionsNav(event) {
149
+ if (!isArrowDownKey(event) && !isArrowUpKey(event)) {
150
+ return;
151
+ }
152
+ if (!this.suggestions.length) {
153
+ return;
154
+ }
155
+ const options = Array.from(this.host.shadowRoot.querySelectorAll("[role='option']")).map((o) => o.id);
156
+ if (!options.length) {
157
+ return;
158
+ }
159
+ event.preventDefault();
160
+ event.stopPropagation();
161
+ if (!this.showSuggestions) {
162
+ this.showSuggestions = true;
163
+ }
164
+ let nextId = null;
165
+ const firstId = options[0];
166
+ const lastId = options[options.length - 1];
167
+ const currOption = options.indexOf(this.activeSuggestion);
168
+ if (currOption < 0) {
169
+ nextId = isArrowDownKey(event) ? firstId : lastId;
170
+ }
171
+ else {
172
+ if (isArrowDownKey(event)) {
173
+ nextId = options[currOption + 1] || lastId;
174
+ }
175
+ else {
176
+ nextId = options[currOption - 1] || firstId;
177
+ }
178
+ }
179
+ this.activeSuggestion = nextId;
180
+ }
181
+ renderSuggestions() {
182
+ 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) => {
183
+ 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) }));
184
+ }))));
185
+ }
75
186
  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" }))));
187
+ return (h(Host, { key: 'd7316fa36a078c2dd1c5888ba35bf004e4c08e6c' }, h("form", { key: '36180991431f49981a4bddd58e4caf0253f326ef', 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: '98862f739245597cd1c22b76c15e2e728a429f17', type: "hidden", name: "area", value: this.searchArea })), h("div", { key: '919e102ea248a41caea96fc3c7289b106d54195d', class: "input-wrapper", role: "none" }, this.searchQuery && (h("button", { key: 'd53357c9b63e6bae5b28809499265a7c332b5f2d', 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: '2ff06d5550f8701e6256f178b925153cac565be8', name: "multiply-circled" }))), h("input", { key: '879339821611ce65bd2777726ebabd0c44384b72', 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.suggestions.length ? '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) => {
188
+ // INFO: prevent ESC from clearing input
189
+ if (isEscKey(e)) {
190
+ e.preventDefault();
191
+ }
192
+ this.handleSuggestionsNav(e);
193
+ } })), h("button", { key: '7101e9eedd9385bfeb5ee41a80d7e6842e75f493', 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: '6e8d065e91e94fba49c64e856129d72155e88b84', name: "search" }))), this.renderSuggestions()));
77
194
  }
78
195
  static get is() { return "zanit-search-form"; }
79
196
  static get encapsulation() { return "shadow"; }
@@ -108,13 +225,61 @@ export class ZanitSearchForm {
108
225
  "setter": false,
109
226
  "reflect": false,
110
227
  "defaultValue": "undefined"
228
+ },
229
+ "searchEnv": {
230
+ "type": "string",
231
+ "attribute": "search-env",
232
+ "mutable": false,
233
+ "complexType": {
234
+ "original": "SearchEnv",
235
+ "resolved": "SearchEnv.DEV | SearchEnv.PROD | SearchEnv.TEST",
236
+ "references": {
237
+ "SearchEnv": {
238
+ "location": "import",
239
+ "path": "../../../utils/subjects.api",
240
+ "id": "src/utils/subjects.api.ts::SearchEnv"
241
+ }
242
+ }
243
+ },
244
+ "required": false,
245
+ "optional": false,
246
+ "docs": {
247
+ "tags": [],
248
+ "text": "Environment for search suggestions"
249
+ },
250
+ "getter": false,
251
+ "setter": false,
252
+ "reflect": false,
253
+ "defaultValue": "SearchEnv.PROD"
254
+ },
255
+ "searchArea": {
256
+ "type": "string",
257
+ "attribute": "search-area",
258
+ "mutable": false,
259
+ "complexType": {
260
+ "original": "string | undefined",
261
+ "resolved": "string",
262
+ "references": {}
263
+ },
264
+ "required": false,
265
+ "optional": true,
266
+ "docs": {
267
+ "tags": [],
268
+ "text": "Search area (e.g. \"SCUOLA\", \"UNIVERSIT\u00C0\", \"DIZIONARI\")."
269
+ },
270
+ "getter": false,
271
+ "setter": false,
272
+ "reflect": false
111
273
  }
112
274
  };
113
275
  }
114
276
  static get states() {
115
277
  return {
116
278
  "showSearchbar": {},
117
- "_searchQuery": {}
279
+ "_searchQuery": {},
280
+ "suggestions": {},
281
+ "activeSuggestion": {},
282
+ "showSuggestions": {}
118
283
  };
119
284
  }
120
285
  static get events() {
@@ -129,9 +294,15 @@ export class ZanitSearchForm {
129
294
  "text": "Emitted on search form submission."
130
295
  },
131
296
  "complexType": {
132
- "original": "{ query: string }",
133
- "resolved": "{ query: string; }",
134
- "references": {}
297
+ "original": "SearchEvent",
298
+ "resolved": "{ query?: string; area?: string; subject?: string; user_query?: string; }",
299
+ "references": {
300
+ "SearchEvent": {
301
+ "location": "import",
302
+ "path": "../../../utils",
303
+ "id": "src/utils/index.ts::SearchEvent"
304
+ }
305
+ }
135
306
  }
136
307
  }, {
137
308
  "method": "resetSearch",
@@ -155,6 +326,15 @@ export class ZanitSearchForm {
155
326
  return [{
156
327
  "propName": "searchQuery",
157
328
  "methodName": "onSearchQueryChange"
329
+ }, {
330
+ "propName": "searchArea",
331
+ "methodName": "onSearchAreaChange"
332
+ }, {
333
+ "propName": "showSearchbar",
334
+ "methodName": "onShowSearchbarChange"
335
+ }, {
336
+ "propName": "showSuggestions",
337
+ "methodName": "onShowSuggestionsChange"
158
338
  }];
159
339
  }
160
340
  static get listeners() {
@@ -166,10 +346,16 @@ export class ZanitSearchForm {
166
346
  "passive": true
167
347
  }, {
168
348
  "name": "keydown",
169
- "method": "handleKeydown",
349
+ "method": "handleEsc",
170
350
  "target": undefined,
171
351
  "capture": false,
172
352
  "passive": true
353
+ }, {
354
+ "name": "keyup",
355
+ "method": "handleTab",
356
+ "target": "document",
357
+ "capture": false,
358
+ "passive": true
173
359
  }];
174
360
  }
175
361
  }
@@ -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 this.showSuggestions = 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 = Array.from(this.host.shadowRoot.querySelectorAll(\"[role='option']\")).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.suggestions.length ? '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}` : `in tutto il sito`}${closeStrong}`;
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":"AAAA,IAAK,WAMJ;AAND,WAAK,WAAW;IACd,gCAAiB,CAAA;IACjB,kDAAyB,CAAA;IACzB,sCAAuB,CAAA;IACvB,sCAAuB,CAAA;IACvB,wCAAyB,CAAA;AAC3B,CAAC,EANI,WAAW,KAAX,WAAW,QAMf;AAED,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AAa5C,MAAM,UAAU,gBAAgB,CAC9B,KAAa,EACb,cAAwC,EACxC,YAAqB;IAErB,MAAM,oBAAoB,GAAG,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,oBAAoB,CAAC,MAAM,GAAG,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAE7D,MAAM,WAAW,GAAuB,EAAE,CAAC;IAE3C,IAAI,YAAY;QAAE,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAE7E,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;IAE7C,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,mBAAmB,GAAG;gBAC1B,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,YAAY,CAAC;gBAC/D,GAAG,oBAAoB;qBACpB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,YAAY,CAAC;qBACvC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;aACrD,CAAC;YACF,mBAAmB,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QACxG,CAAC;aAAM,CAAC;YACN,oBAAoB;iBACjB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;iBACjD,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QACrG,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,mBAAmB,GAAG,CAAC,UAAkB,EAAE,IAAa,EAAoB,EAAE;IAClF,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,QAAQ,UAAU,IAAI,IAAI,EAAE,CAAC;QACzC,KAAK,EAAE,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC;QACjD,UAAU,EAAE,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC;QACrD,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;QACvE,GAAG,WAAW,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,CAAC;KAC7C,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,UAAkB,EAAE,IAAY,EAAE,OAAe,EAAoB,EAAE;IACrG,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,QAAQ,UAAU,IAAI,IAAI,IAAI,OAAO,EAAE,CAAC;QACpD,KAAK,EAAE,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC;QAChD,UAAU,EAAE,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;QACpD,GAAG,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;QACrD,GAAG,WAAW,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC;KACrD,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,MAAc,EAAE,EAAE,CACjC,MAAM;KACH,KAAK,CAAC,EAAE,CAAC;KACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;KACxC,IAAI,CAAC,EAAE,CAAC,CAAC;AAEd,MAAM,QAAQ,GAAG,CAAC,MAA8B,EAAU,EAAE;IAC1D,OAAO,WAAW,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC;AAC7D,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,UAAkB,EAAE,KAAc,EAAE,IAAa,EAAE,OAAgB,EAAE,EAAE,CAAC,CAAC;IAC5F,UAAU;IACV,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACzB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;CAChC,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,CAAC,UAAkB,EAAE,IAAa,EAAE,YAAqB,KAAK,EAAE,SAAkB,KAAK,EAAE,EAAE;IAC5G,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5C,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAE9C,OAAO,YAAY,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,IAAI,UAAU,GAAG,UAAU,GAAG,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,gBAAgB,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,kBAAkB,GAAG,WAAW,EAAE,CAAC;AACvM,CAAC,CAAC;AAEF,SAAS,gBAAgB,CAAC,KAAa,EAAE,cAAwC;IAC/E,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC;SAClC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC,CAAC;SAC5F,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,6DAA6D;AAC7D,MAAM,WAAW,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAExE,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAAE;IACpC,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;AAClC,CAAC,CAAC","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}` : `in tutto il sito`}${closeStrong}`;\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