@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.
- package/dist/cjs/{index-q1XSBSqA.js → index-CRwLFnL1.js} +7 -3
- package/dist/cjs/index-CRwLFnL1.js.map +1 -0
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/zanichelli-it-frontend-kit.cjs.js +2 -2
- package/dist/cjs/zanit-menubar.zanit-mobile-menubar.zanit-search-form.entry.cjs.js.map +1 -1
- package/dist/cjs/zanit-menubar_3.cjs.entry.js +266 -22
- package/dist/cjs/zanit-menubar_3.cjs.entry.js.map +1 -1
- package/dist/collection/components/menubar/menubar.css +1 -0
- package/dist/collection/components/menubar/menubar.js +53 -2
- package/dist/collection/components/menubar/menubar.js.map +1 -1
- package/dist/collection/components/menubar/mobile-menubar/mobile-menubar.js +52 -1
- package/dist/collection/components/menubar/mobile-menubar/mobile-menubar.js.map +1 -1
- package/dist/collection/components/menubar/search-form/search-form.css +51 -0
- package/dist/collection/components/menubar/search-form/search-form.js +207 -22
- package/dist/collection/components/menubar/search-form/search-form.js.map +1 -1
- package/dist/collection/components/menubar/search-form/suggestions.js +84 -0
- package/dist/collection/components/menubar/search-form/suggestions.js.map +1 -0
- package/dist/collection/utils/subjects.api.js +25 -0
- package/dist/collection/utils/subjects.api.js.map +1 -0
- package/dist/collection/utils/utils.js +8 -0
- package/dist/collection/utils/utils.js.map +1 -1
- package/dist/components/index.js +5 -2
- package/dist/components/index.js.map +1 -1
- package/dist/components/p-Bk8_DaVU.js +375 -0
- package/dist/components/p-Bk8_DaVU.js.map +1 -0
- package/dist/components/{p-DCsoOA4v.js → p-Cs52y6qp.js} +12 -5
- package/dist/components/p-Cs52y6qp.js.map +1 -0
- package/dist/components/zanit-menubar.js +13 -6
- package/dist/components/zanit-menubar.js.map +1 -1
- package/dist/components/zanit-mobile-menubar.js +1 -1
- package/dist/components/zanit-search-form.js +1 -1
- package/dist/esm/{index-CaWL2omE.js → index-B82IapZZ.js} +7 -4
- package/dist/esm/index-B82IapZZ.js.map +1 -0
- package/dist/esm/loader.js +3 -3
- package/dist/esm/zanichelli-it-frontend-kit.js +3 -3
- package/dist/esm/zanit-menubar.zanit-mobile-menubar.zanit-search-form.entry.js.map +1 -1
- package/dist/esm/zanit-menubar_3.entry.js +266 -22
- package/dist/esm/zanit-menubar_3.entry.js.map +1 -1
- package/dist/types/components/menubar/menubar.d.ts +5 -0
- package/dist/types/components/menubar/mobile-menubar/mobile-menubar.d.ts +5 -0
- package/dist/types/components/menubar/search-form/search-form.d.ts +28 -5
- package/dist/types/components/menubar/search-form/suggestions.d.ts +11 -0
- package/dist/types/components.d.ts +60 -4
- package/dist/types/utils/subjects.api.d.ts +6 -0
- package/dist/types/utils/types.d.ts +7 -0
- package/dist/types/utils/utils.d.ts +8 -0
- package/dist/zanichelli-it-frontend-kit/p-1dddc763.entry.js +2 -0
- package/dist/zanichelli-it-frontend-kit/p-1dddc763.entry.js.map +1 -0
- package/{www/build/p-CaWL2omE.js → dist/zanichelli-it-frontend-kit/p-B82IapZZ.js} +2 -2
- package/dist/zanichelli-it-frontend-kit/p-B82IapZZ.js.map +1 -0
- package/dist/zanichelli-it-frontend-kit/zanichelli-it-frontend-kit.esm.js +1 -1
- package/dist/zanichelli-it-frontend-kit/zanit-menubar.zanit-mobile-menubar.zanit-search-form.entry.esm.js.map +1 -1
- package/package.json +11 -12
- package/www/build/p-1dddc763.entry.js +2 -0
- package/www/build/p-1dddc763.entry.js.map +1 -0
- package/{dist/zanichelli-it-frontend-kit/p-CaWL2omE.js → www/build/p-B82IapZZ.js} +2 -2
- package/www/build/p-B82IapZZ.js.map +1 -0
- package/www/build/p-d121e671.js +2 -0
- package/www/build/zanichelli-it-frontend-kit.esm.js +1 -1
- package/www/build/zanit-menubar.zanit-mobile-menubar.zanit-search-form.entry.esm.js.map +1 -1
- package/www/index.html +5 -1
- package/dist/cjs/index-q1XSBSqA.js.map +0 -1
- package/dist/components/p-C_SXGfG9.js +0 -133
- package/dist/components/p-C_SXGfG9.js.map +0 -1
- package/dist/components/p-DCsoOA4v.js.map +0 -1
- package/dist/esm/index-CaWL2omE.js.map +0 -1
- package/dist/zanichelli-it-frontend-kit/p-217f87ff.entry.js +0 -2
- package/dist/zanichelli-it-frontend-kit/p-217f87ff.entry.js.map +0 -1
- package/dist/zanichelli-it-frontend-kit/p-CaWL2omE.js.map +0 -1
- package/www/build/p-1d74b708.js +0 -2
- package/www/build/p-217f87ff.entry.js +0 -2
- package/www/build/p-217f87ff.entry.js.map +0 -1
- 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.
|
|
54
|
+
if (this.showSearchbar && this.host && !containsTarget(this.host, event)) {
|
|
28
55
|
this.showSearchbar = false;
|
|
29
56
|
}
|
|
30
57
|
}
|
|
31
|
-
/** Close the
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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: '
|
|
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": "
|
|
133
|
-
"resolved": "{ query
|
|
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": "
|
|
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"]}
|
package/dist/components/index.js
CHANGED
|
@@ -214,7 +214,10 @@ var unwrapErr = (result) => {
|
|
|
214
214
|
}
|
|
215
215
|
};
|
|
216
216
|
function createShadowRoot(cmpMeta) {
|
|
217
|
-
const shadowRoot = this.attachShadow({
|
|
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
|