@fluid-topics/ft-search-bar 0.3.0 → 0.3.3

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.
@@ -1627,9 +1627,9 @@ const V=Symbol.for(""),K=t=>{if((null==t?void 0:t.r)===V)return null==t?void 0:t
1627
1627
  @keydown=${e=>this.onOptionKeyDown(e,t)}
1628
1628
  @click=${()=>this.selectOption(t)}>
1629
1629
  <ft-ripple ?primary=${e} ?activated=${e}></ft-ripple>
1630
- ${t.label}
1630
+ <span>${t.label}</span>
1631
1631
  </div>
1632
- `}updated(t){var e;super.updated(t),t.has("options")&&(this.selectedOption=this.options.filter((t=>t.selected))[0]),t.has("selectedOption")&&(this.optionsDisplayed=!1,this.dispatchEvent(new CustomEvent("change",{detail:null===(e=this.selectedOption)||void 0===e?void 0:e.value}))),t.has("optionsDisplayed")&&this.fixedMenuPosition&&this.hasOptionsMenuOpen&&this.positionOptionsMenu()}positionOptionsMenu(){this.optionsMenu.style.top=this.mainPanel.getBoundingClientRect().top+this.mainPanel.getBoundingClientRect().height+"px",this.optionsMenu.style.left=this.mainPanel.getBoundingClientRect().left+"px",this.optionsMenu.style.minWidth=this.mainPanel.getBoundingClientRect().width+"px"}contentAvailableCallback(t){var e,i;t.has("focusOptions")&&this.focusOptions&&(null===(i=null!==(e=this.selectedOptionElement)&&void 0!==e?e:this.firstOption)||void 0===i||i.focus(),this.focusOptions=!1)}get hasOptionsMenuOpen(){return!this.disabled&&this.optionsDisplayed&&this.hasOptions}get hasOptions(){return this.options.length>0}updateOptionsFromSlot(t){var e;t.stopPropagation();let i=null===(e=this.optionsSlot)||void 0===e?void 0:e.assignedElements().map((t=>t));i&&i.length>0&&(this.options=i)}onMainPanelKeyDown(t){switch(t.key){case" ":t.preventDefault(),t.stopPropagation();case"Enter":this.optionsDisplayed=!this.optionsDisplayed,this.focusOptions=!0;break;case"ArrowUp":case"ArrowDown":t.preventDefault(),t.stopPropagation(),this.optionsDisplayed=!0,this.focusOptions=!0}}onOptionsKeyDown(t){var e,i,o,s,r;let n;switch(t.key){case"Escape":this.optionsDisplayed=!1,null===(e=this.mainPanel)||void 0===e||e.focus();break;case"Tab":this.optionsDisplayed=!1;break;case"ArrowUp":t.preventDefault(),t.stopPropagation(),n=null!==(o=null===(i=this.focusedOption)||void 0===i?void 0:i.previousElementSibling)&&void 0!==o?o:this.lastOption;break;case"ArrowDown":t.preventDefault(),t.stopPropagation(),n=null!==(r=null===(s=this.focusedOption)||void 0===s?void 0:s.nextElementSibling)&&void 0!==r?r:this.firstOption}null==n||n.focus()}onOptionKeyDown(t,e){var i;"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),t.stopPropagation(),this.selectOption(e),this.optionsDisplayed=!1,null===(i=this.mainPanel)||void 0===i||i.focus())}selectOption(t){this.selectedOption=t;for(let e of this.options)e.selected=e===t}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this.hideOptions)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("click",this.hideOptions)}}Mi.elementDefinitions={"ft-input-label":Di,"ft-typography":Yt,"ft-ripple":pe,"ft-icon":Se},Mi.styles=[Kt,qt,i.css`
1632
+ `}updated(t){var e;super.updated(t),t.has("options")&&(this.selectedOption=this.options.filter((t=>t.selected))[0]),t.has("selectedOption")&&(this.optionsDisplayed=!1,this.dispatchEvent(new CustomEvent("change",{detail:null===(e=this.selectedOption)||void 0===e?void 0:e.value}))),t.has("optionsDisplayed")&&this.fixedMenuPosition&&this.hasOptionsMenuOpen&&this.positionOptionsMenu()}positionOptionsMenu(){this.optionsMenu.style.top=this.mainPanel.getBoundingClientRect().top+this.mainPanel.getBoundingClientRect().height+"px",this.optionsMenu.style.left=this.mainPanel.getBoundingClientRect().left+"px",this.optionsMenu.style.width=this.mainPanel.getBoundingClientRect().width+"px"}contentAvailableCallback(t){var e,i;t.has("focusOptions")&&this.focusOptions&&(null===(i=null!==(e=this.selectedOptionElement)&&void 0!==e?e:this.firstOption)||void 0===i||i.focus(),this.focusOptions=!1)}get hasOptionsMenuOpen(){return!this.disabled&&this.optionsDisplayed&&this.hasOptions}get hasOptions(){return this.options.length>0}updateOptionsFromSlot(t){var e;t.stopPropagation();let i=null===(e=this.optionsSlot)||void 0===e?void 0:e.assignedElements().map((t=>t));i&&i.length>0&&(this.options=i)}onMainPanelKeyDown(t){switch(t.key){case" ":t.preventDefault(),t.stopPropagation();case"Enter":this.optionsDisplayed=!this.optionsDisplayed,this.focusOptions=!0;break;case"ArrowUp":case"ArrowDown":t.preventDefault(),t.stopPropagation(),this.optionsDisplayed=!0,this.focusOptions=!0}}onOptionsKeyDown(t){var e,i,o,s,r;let n;switch(t.key){case"Escape":this.optionsDisplayed=!1,null===(e=this.mainPanel)||void 0===e||e.focus();break;case"Tab":this.optionsDisplayed=!1;break;case"ArrowUp":t.preventDefault(),t.stopPropagation(),n=null!==(o=null===(i=this.focusedOption)||void 0===i?void 0:i.previousElementSibling)&&void 0!==o?o:this.lastOption;break;case"ArrowDown":t.preventDefault(),t.stopPropagation(),n=null!==(r=null===(s=this.focusedOption)||void 0===s?void 0:s.nextElementSibling)&&void 0!==r?r:this.firstOption}null==n||n.focus()}onOptionKeyDown(t,e){var i;"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),t.stopPropagation(),this.selectOption(e),this.optionsDisplayed=!1,null===(i=this.mainPanel)||void 0===i||i.focus())}selectOption(t){this.selectedOption=t;for(let e of this.options)e.selected=e===t}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this.hideOptions)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("click",this.hideOptions)}}Mi.elementDefinitions={"ft-input-label":Di,"ft-typography":Yt,"ft-ripple":pe,"ft-icon":Se},Mi.styles=[Kt,qt,i.css`
1633
1633
  *:focus {
1634
1634
  outline: none;
1635
1635
  }
@@ -1763,6 +1763,11 @@ const V=Symbol.for(""),K=t=>{if((null==t?void 0:t.r)===V)return null==t?void 0:t
1763
1763
  align-items: center;
1764
1764
  }
1765
1765
 
1766
+ .ft-select--option span {
1767
+ text-overflow: ellipsis;
1768
+ overflow: hidden;
1769
+ }
1770
+
1766
1771
  .ft-select--helper-text {
1767
1772
  padding: 0 12px 0 16px;
1768
1773
  color: ${ji.helperColor};
@@ -1747,9 +1747,9 @@ class ui extends zt{constructor(t){if(super(t),this.it=q,t.type!==Ct)throw Error
1747
1747
  @keydown=${e=>this.onOptionKeyDown(e,t)}
1748
1748
  @click=${()=>this.selectOption(t)}>
1749
1749
  <ft-ripple ?primary=${e} ?activated=${e}></ft-ripple>
1750
- ${t.label}
1750
+ <span>${t.label}</span>
1751
1751
  </div>
1752
- `}updated(t){var e;super.updated(t),t.has("options")&&(this.selectedOption=this.options.filter((t=>t.selected))[0]),t.has("selectedOption")&&(this.optionsDisplayed=!1,this.dispatchEvent(new CustomEvent("change",{detail:null===(e=this.selectedOption)||void 0===e?void 0:e.value}))),t.has("optionsDisplayed")&&this.fixedMenuPosition&&this.hasOptionsMenuOpen&&this.positionOptionsMenu()}positionOptionsMenu(){this.optionsMenu.style.top=this.mainPanel.getBoundingClientRect().top+this.mainPanel.getBoundingClientRect().height+"px",this.optionsMenu.style.left=this.mainPanel.getBoundingClientRect().left+"px",this.optionsMenu.style.minWidth=this.mainPanel.getBoundingClientRect().width+"px"}contentAvailableCallback(t){var e,i;t.has("focusOptions")&&this.focusOptions&&(null===(i=null!==(e=this.selectedOptionElement)&&void 0!==e?e:this.firstOption)||void 0===i||i.focus(),this.focusOptions=!1)}get hasOptionsMenuOpen(){return!this.disabled&&this.optionsDisplayed&&this.hasOptions}get hasOptions(){return this.options.length>0}updateOptionsFromSlot(t){var e;t.stopPropagation();let i=null===(e=this.optionsSlot)||void 0===e?void 0:e.assignedElements().map((t=>t));i&&i.length>0&&(this.options=i)}onMainPanelKeyDown(t){switch(t.key){case" ":t.preventDefault(),t.stopPropagation();case"Enter":this.optionsDisplayed=!this.optionsDisplayed,this.focusOptions=!0;break;case"ArrowUp":case"ArrowDown":t.preventDefault(),t.stopPropagation(),this.optionsDisplayed=!0,this.focusOptions=!0}}onOptionsKeyDown(t){var e,i,o,s,n;let r;switch(t.key){case"Escape":this.optionsDisplayed=!1,null===(e=this.mainPanel)||void 0===e||e.focus();break;case"Tab":this.optionsDisplayed=!1;break;case"ArrowUp":t.preventDefault(),t.stopPropagation(),r=null!==(o=null===(i=this.focusedOption)||void 0===i?void 0:i.previousElementSibling)&&void 0!==o?o:this.lastOption;break;case"ArrowDown":t.preventDefault(),t.stopPropagation(),r=null!==(n=null===(s=this.focusedOption)||void 0===s?void 0:s.nextElementSibling)&&void 0!==n?n:this.firstOption}null==r||r.focus()}onOptionKeyDown(t,e){var i;"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),t.stopPropagation(),this.selectOption(e),this.optionsDisplayed=!1,null===(i=this.mainPanel)||void 0===i||i.focus())}selectOption(t){this.selectedOption=t;for(let e of this.options)e.selected=e===t}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this.hideOptions)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("click",this.hideOptions)}}Do.elementDefinitions={"ft-input-label":Fo,"ft-typography":Ve,"ft-ripple":ai,"ft-icon":ki},Do.styles=[_e,He,g`
1752
+ `}updated(t){var e;super.updated(t),t.has("options")&&(this.selectedOption=this.options.filter((t=>t.selected))[0]),t.has("selectedOption")&&(this.optionsDisplayed=!1,this.dispatchEvent(new CustomEvent("change",{detail:null===(e=this.selectedOption)||void 0===e?void 0:e.value}))),t.has("optionsDisplayed")&&this.fixedMenuPosition&&this.hasOptionsMenuOpen&&this.positionOptionsMenu()}positionOptionsMenu(){this.optionsMenu.style.top=this.mainPanel.getBoundingClientRect().top+this.mainPanel.getBoundingClientRect().height+"px",this.optionsMenu.style.left=this.mainPanel.getBoundingClientRect().left+"px",this.optionsMenu.style.width=this.mainPanel.getBoundingClientRect().width+"px"}contentAvailableCallback(t){var e,i;t.has("focusOptions")&&this.focusOptions&&(null===(i=null!==(e=this.selectedOptionElement)&&void 0!==e?e:this.firstOption)||void 0===i||i.focus(),this.focusOptions=!1)}get hasOptionsMenuOpen(){return!this.disabled&&this.optionsDisplayed&&this.hasOptions}get hasOptions(){return this.options.length>0}updateOptionsFromSlot(t){var e;t.stopPropagation();let i=null===(e=this.optionsSlot)||void 0===e?void 0:e.assignedElements().map((t=>t));i&&i.length>0&&(this.options=i)}onMainPanelKeyDown(t){switch(t.key){case" ":t.preventDefault(),t.stopPropagation();case"Enter":this.optionsDisplayed=!this.optionsDisplayed,this.focusOptions=!0;break;case"ArrowUp":case"ArrowDown":t.preventDefault(),t.stopPropagation(),this.optionsDisplayed=!0,this.focusOptions=!0}}onOptionsKeyDown(t){var e,i,o,s,n;let r;switch(t.key){case"Escape":this.optionsDisplayed=!1,null===(e=this.mainPanel)||void 0===e||e.focus();break;case"Tab":this.optionsDisplayed=!1;break;case"ArrowUp":t.preventDefault(),t.stopPropagation(),r=null!==(o=null===(i=this.focusedOption)||void 0===i?void 0:i.previousElementSibling)&&void 0!==o?o:this.lastOption;break;case"ArrowDown":t.preventDefault(),t.stopPropagation(),r=null!==(n=null===(s=this.focusedOption)||void 0===s?void 0:s.nextElementSibling)&&void 0!==n?n:this.firstOption}null==r||r.focus()}onOptionKeyDown(t,e){var i;"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),t.stopPropagation(),this.selectOption(e),this.optionsDisplayed=!1,null===(i=this.mainPanel)||void 0===i||i.focus())}selectOption(t){this.selectedOption=t;for(let e of this.options)e.selected=e===t}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this.hideOptions)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("click",this.hideOptions)}}Do.elementDefinitions={"ft-input-label":Fo,"ft-typography":Ve,"ft-ripple":ai,"ft-icon":ki},Do.styles=[_e,He,g`
1753
1753
  *:focus {
1754
1754
  outline: none;
1755
1755
  }
@@ -1883,6 +1883,11 @@ class ui extends zt{constructor(t){if(super(t),this.it=q,t.type!==Ct)throw Error
1883
1883
  align-items: center;
1884
1884
  }
1885
1885
 
1886
+ .ft-select--option span {
1887
+ text-overflow: ellipsis;
1888
+ overflow: hidden;
1889
+ }
1890
+
1886
1891
  .ft-select--helper-text {
1887
1892
  padding: 0 12px 0 16px;
1888
1893
  color: ${Lo.helperColor};
@@ -0,0 +1,16 @@
1
+ import { FtSearchBar } from "../ft-search-bar";
2
+ import { FacetsChipsManager } from "./FacetsChipsManager";
3
+ import { SuggestManager } from "./SuggestManager";
4
+ export declare class DesktopSearchBarManager {
5
+ private searchBar;
6
+ private selectedFacetsManager;
7
+ private suggestManager;
8
+ constructor(searchBar: FtSearchBar, selectedFacetsManager?: FacetsChipsManager, suggestManager?: SuggestManager);
9
+ static styles: import("lit").CSSResult;
10
+ render(): import("lit-html").TemplateResult<1>;
11
+ private renderSearchBarLeftAction;
12
+ private renderDesktopSearchBarButtons;
13
+ private onSearchBarKeyDown;
14
+ private onSearchBarKeyUp;
15
+ }
16
+ //# sourceMappingURL=DesktopSearchBarManager.d.ts.map
@@ -0,0 +1,131 @@
1
+ import { css, html, nothing } from "lit";
2
+ import { repeat } from "lit/directives/repeat.js";
3
+ import { FacetsChipsManager } from "./FacetsChipsManager";
4
+ import { SuggestManager } from "./SuggestManager";
5
+ import { classMap } from "lit/directives/class-map.js";
6
+ export class DesktopSearchBarManager {
7
+ constructor(searchBar, selectedFacetsManager, suggestManager) {
8
+ this.searchBar = searchBar;
9
+ this.selectedFacetsManager = selectedFacetsManager !== null && selectedFacetsManager !== void 0 ? selectedFacetsManager : new FacetsChipsManager(searchBar);
10
+ this.suggestManager = suggestManager !== null && suggestManager !== void 0 ? suggestManager : new SuggestManager(searchBar);
11
+ }
12
+ render() {
13
+ const rootClasses = {
14
+ "ft-search-bar--container": true,
15
+ "ft-search-bar--dense": this.searchBar.dense,
16
+ "ft-search-bar--desktop": true,
17
+ "ft-search-bar--floating-panel-open": this.searchBar.displayFacets && !this.searchBar.forceMenuOpen,
18
+ "ft-search-bar--forced-open": this.searchBar.forceMenuOpen
19
+ };
20
+ return html `
21
+ <div class="${classMap(rootClasses)}" part="container" tabindex="-1">
22
+ <div class="ft-search-bar" part="search-bar">
23
+ ${(this.renderSearchBarLeftAction())}
24
+ <div class="ft-search-bar--input-container" part="input-container" tabindex="-1">
25
+ <div class="ft-search-bar--input-outline" part="input-outline">
26
+ ${this.searchBar.dense ? this.selectedFacetsManager.render() : nothing}
27
+ <input class="ft-search-bar--input ft-typography--body2"
28
+ part="input"
29
+ type="text"
30
+ placeholder="${this.searchBar.labelResolver.resolve("inputPlaceHolder")}"
31
+ value="${this.searchBar.query}"
32
+ @keydown=${(e) => this.onSearchBarKeyDown(e)}
33
+ @keyup=${(e) => this.onSearchBarKeyUp(e)}>
34
+ </div>
35
+ ${this.suggestManager.render()}
36
+ </div>
37
+ ${this.renderDesktopSearchBarButtons()}
38
+ ${this.searchBar.renderDesktopFloatingMenu()}
39
+ </div>
40
+ ${this.searchBar.dense
41
+ ? nothing
42
+ : this.searchBar.forceMenuOpen ? this.searchBar.renderDesktopMenu()
43
+ : this.selectedFacetsManager.render()}
44
+ </div>
45
+ `;
46
+ }
47
+ renderSearchBarLeftAction() {
48
+ if (this.searchBar.hasFacets()) {
49
+ return this.searchBar.forceMenuOpen ? nothing : html `
50
+ <ft-button class="ft-search-bar--filters-opener ft-search-bar--left-action"
51
+ part="filters-opener"
52
+ trailingIcon
53
+ icon="${this.searchBar.displayFacets ? "expand_less" : "expand_more"}"
54
+ @click=${(e) => {
55
+ e.stopPropagation();
56
+ this.searchBar.displayFacets = !this.searchBar.displayFacets;
57
+ }}
58
+ @focusin=${(e) => e.stopPropagation()}>
59
+ ${this.searchBar.labelResolver.resolve("filtersButton")}
60
+ </ft-button>
61
+ `;
62
+ }
63
+ else if (this.searchBar.hasLocaleSelector()) {
64
+ return html `
65
+ <ft-select outlined
66
+ class="ft-search-bar--content-locale ft-search-bar--left-action"
67
+ part="content-locale select-ft-locale"
68
+ .exportpartsPrefixes=${["content-locale", "select-ft-locale"]}
69
+ @change=${(e) => this.searchBar.contentLocale = e.detail == null ? undefined : e.detail}>
70
+ ${repeat(this.searchBar.availableContentLocales, l => l.lang, l => html `
71
+ <ft-select-option .value=${l.lang}
72
+ label="${l.label}"
73
+ ?selected=${l.lang === this.searchBar.contentLocale}>
74
+ </ft-select-option>
75
+ `)}
76
+ </ft-select>
77
+ `;
78
+ }
79
+ return nothing;
80
+ }
81
+ renderDesktopSearchBarButtons() {
82
+ return html `
83
+ <div class="ft-search-bar--actions"
84
+ part="search-bar-actions">
85
+ ${this.searchBar.query ? html `
86
+ <ft-button class="ft-search-bar--clear-query"
87
+ part="clear-query"
88
+ icon="close"
89
+ round dense
90
+ label="${this.searchBar.labelResolver.resolve("clearInputButton")}"
91
+ @click=${() => this.searchBar.setQuery("")}
92
+ ></ft-button>
93
+ <div class="ft-search-bar--separator"></div>
94
+ ` : null}
95
+ <ft-button class="ft-search-bar--launch-search"
96
+ part="launch-search-in-bar"
97
+ icon="search"
98
+ round dense
99
+ label="${this.searchBar.labelResolver.resolve("searchButton")}"
100
+ @click=${() => this.searchBar.launchSearch()}
101
+ ></ft-button>
102
+ </div>
103
+ `;
104
+ }
105
+ onSearchBarKeyDown(e) {
106
+ var _a;
107
+ switch (e.key) {
108
+ case "Escape":
109
+ this.searchBar.mobileMenuOpen = false;
110
+ (_a = this.searchBar.input) === null || _a === void 0 ? void 0 : _a.blur();
111
+ break;
112
+ case "ArrowDown":
113
+ e.stopPropagation();
114
+ e.preventDefault();
115
+ this.suggestManager.focusFirstSuggestion();
116
+ break;
117
+ }
118
+ }
119
+ onSearchBarKeyUp(e) {
120
+ const input = e.composedPath()[0];
121
+ this.searchBar.query = input.value;
122
+ if (e.key === "Enter") {
123
+ this.searchBar.launchSearch();
124
+ }
125
+ }
126
+ }
127
+ //language=css
128
+ DesktopSearchBarManager.styles = css `
129
+
130
+ `;
131
+ //# sourceMappingURL=DesktopSearchBarManager.js.map
@@ -0,0 +1,10 @@
1
+ import type { FtSearchBar } from "../ft-search-bar";
2
+ export declare class FacetsChipsManager {
3
+ private searchBar;
4
+ constructor(searchBar: FtSearchBar);
5
+ static styles: import("lit").CSSResult;
6
+ render(): import("lit-html").TemplateResult<1>;
7
+ private openMobileFilters;
8
+ getLocaleLabel(locale: string | undefined): string | undefined;
9
+ }
10
+ //# sourceMappingURL=FacetsChipsManager.d.ts.map
@@ -0,0 +1,129 @@
1
+ import { css, html, nothing } from "lit";
2
+ import { repeat } from "lit/directives/repeat.js";
3
+ import { getBreadcrumbFromValue, getLabelFromValue, getSelectedValues } from "../converters";
4
+ import { setVariable } from "@fluid-topics/ft-wc-utils";
5
+ import { FtSnapScrollCssVariables } from "@fluid-topics/ft-snap-scroll";
6
+ import { FtChipCssVariables } from "@fluid-topics/ft-chip";
7
+ export class FacetsChipsManager {
8
+ constructor(searchBar) {
9
+ this.searchBar = searchBar;
10
+ }
11
+ render() {
12
+ if (!this.searchBar.hasLocaleSelector() && !this.searchBar.hasFacets()) {
13
+ return html ``;
14
+ }
15
+ const isMobile = this.searchBar.isMobile();
16
+ const useSnapScroll = (!isMobile && this.searchBar.dense) || (isMobile && this.searchBar.isMobileMenuOpen());
17
+ const filters = html `
18
+ ${this.searchBar.hasLocaleSelector() && (this.searchBar.hasFacets() || isMobile) ? html `
19
+ <ft-chip part="selected-filters selected-filter-ft-locale"
20
+ ?dense=${this.searchBar.dense && !isMobile}
21
+ ?clickable=${isMobile}
22
+ @click=${() => this.openMobileFilters("ft:locale")}
23
+ data-key="ft:locale"
24
+ data-value="${this.searchBar.contentLocale}">
25
+ ${(this.getLocaleLabel(this.searchBar.contentLocale))}
26
+ </ft-chip>
27
+ ` : null}
28
+ ${repeat(this.searchBar.facets, facet => facet.key, facet => {
29
+ const values = getSelectedValues(facet);
30
+ return repeat(values, value => {
31
+ let label = facet.label + ": " + getBreadcrumbFromValue(value);
32
+ const keyWithNoColumn = facet.key.replace(":", "-");
33
+ const chip = html `
34
+ <ft-chip
35
+ part="selected-filters selected-filter-${keyWithNoColumn}"
36
+ ?dense=${this.searchBar.dense && !isMobile}
37
+ ?clickable=${isMobile}
38
+ ?removable=${!isMobile}
39
+ icon=${isMobile ? nothing : "close"}
40
+ label="${label}"
41
+ title=${useSnapScroll ? label : nothing}
42
+ @click=${() => this.openMobileFilters(facet.key)}
43
+ @icon-click=${() => this.searchBar.setFilter(facet.key, values.filter(v => v !== value))}
44
+ data-key="${facet.key}"
45
+ data-value="${value}">
46
+ ${getLabelFromValue(value)}
47
+ </ft-chip>
48
+ `;
49
+ return useSnapScroll ? chip : html `
50
+ <ft-tooltip inline text="${label}">
51
+ ${chip}
52
+ </ft-tooltip>
53
+ `;
54
+ });
55
+ })}
56
+ ${isMobile ? html `
57
+ <ft-chip part="selected-filters mobile-filters-opener"
58
+ icon="add"
59
+ clickable
60
+ @click=${() => {
61
+ this.searchBar.mobileMenuOpen = true;
62
+ this.searchBar.displayFacets = true;
63
+ }}>
64
+ ${this.searchBar.labelResolver.resolve("filtersButton")}
65
+ </ft-chip>
66
+ ` : nothing}
67
+ `;
68
+ return useSnapScroll
69
+ ? html `
70
+ <ft-snap-scroll horizontal controls hideScrollbar limitSize
71
+ class="ft-search-bar--selected-filters"
72
+ part="selected-filters-container"
73
+ exportpartsPrefix="selected-filters-container">
74
+ ${filters}
75
+ </ft-snap-scroll>
76
+ `
77
+ : html `
78
+ <div class="ft-search-bar--selected-filters" part="selected-filters-container">
79
+ ${filters}
80
+ </div>
81
+ `;
82
+ }
83
+ openMobileFilters(filterKey) {
84
+ if (this.searchBar.isMobile()) {
85
+ this.searchBar.mobileMenuOpen = true;
86
+ this.searchBar.displayFacets = true;
87
+ this.searchBar.scrollToFacet = filterKey;
88
+ }
89
+ }
90
+ getLocaleLabel(locale) {
91
+ var _a;
92
+ return (_a = this.searchBar.availableContentLocales.filter(l => { var _a; return ((_a = l.lang) !== null && _a !== void 0 ? _a : "").toLowerCase() === (locale !== null && locale !== void 0 ? locale : "").toLowerCase(); })
93
+ .map(l => l.label)
94
+ .pop()) !== null && _a !== void 0 ? _a : locale;
95
+ }
96
+ }
97
+ //language=css
98
+ FacetsChipsManager.styles = css `
99
+ .ft-search-bar--selected-filters:not(ft-snap-scroll) {
100
+ flex-shrink: 0;
101
+ display: flex;
102
+ flex-direction: row;
103
+ flex-wrap: wrap;
104
+ gap: 8px;
105
+ }
106
+
107
+ ft-snap-scroll.ft-search-bar--selected-filters {
108
+ overflow: hidden;
109
+ ${setVariable(FtSnapScrollCssVariables.gap, "4px")};
110
+ }
111
+
112
+ ft-snap-scroll.ft-search-bar--selected-filters::part(content) {
113
+ align-items: center;
114
+ }
115
+
116
+ .ft-search-bar--desktop ft-snap-scroll.ft-search-bar--selected-filters {
117
+ ${setVariable(FtChipCssVariables.iconSize, "17px")};
118
+ ${setVariable(FtChipCssVariables.fontSize, "12px")};
119
+ }
120
+
121
+ .ft-search-bar--selected-filters * {
122
+ max-width: 100%;
123
+ }
124
+
125
+ .ft-search-bar--selected-filters ft-chip {
126
+ flex-grow: 0;
127
+ }
128
+ `;
129
+ //# sourceMappingURL=FacetsChipsManager.js.map
@@ -0,0 +1,14 @@
1
+ import { FtSearchBar } from "../ft-search-bar";
2
+ import { FacetsChipsManager } from "./FacetsChipsManager";
3
+ import { SuggestManager } from "./SuggestManager";
4
+ export declare class MobileSearchBarManager {
5
+ private searchBar;
6
+ private selectedFacetsManager;
7
+ private suggestManager;
8
+ constructor(searchBar: FtSearchBar, selectedFacetsManager?: FacetsChipsManager, suggestManager?: SuggestManager);
9
+ static styles: import("lit").CSSResult;
10
+ render(): import("lit-html").TemplateResult<1>;
11
+ private renderMobileSearchBarButtons;
12
+ private onSearchBarKeyUp;
13
+ }
14
+ //# sourceMappingURL=MobileSearchBarManager.d.ts.map
@@ -0,0 +1,92 @@
1
+ import { css, html, nothing } from "lit";
2
+ import { FacetsChipsManager } from "./FacetsChipsManager";
3
+ import { SuggestManager } from "./SuggestManager";
4
+ import { classMap } from "lit/directives/class-map.js";
5
+ export class MobileSearchBarManager {
6
+ constructor(searchBar, selectedFacetsManager, suggestManager) {
7
+ this.searchBar = searchBar;
8
+ this.selectedFacetsManager = selectedFacetsManager !== null && selectedFacetsManager !== void 0 ? selectedFacetsManager : new FacetsChipsManager(searchBar);
9
+ this.suggestManager = suggestManager !== null && suggestManager !== void 0 ? suggestManager : new SuggestManager(searchBar);
10
+ }
11
+ render() {
12
+ const rootClasses = {
13
+ "ft-search-bar--container": true,
14
+ "ft-search-bar--mobile": true,
15
+ "ft-search-bar--mobile-menu-open": this.searchBar.isMobileMenuOpen(),
16
+ "ft-search-bar--forced-open": this.searchBar.forceMobileMenuOpen,
17
+ };
18
+ return html `
19
+ <div class="${classMap(rootClasses)}" part="container" tabindex="-1">
20
+ <div class="ft-search-bar">
21
+ <div class="ft-search-bar--input-container" part="input-container">
22
+ <div class="ft-search-bar--input-outline" part="input-outline">
23
+ <input class="ft-search-bar--input ft-typography--body2"
24
+ part="input"
25
+ type="text"
26
+ placeholder="${this.searchBar.labelResolver.resolve("inputPlaceHolder")}"
27
+ value="${this.searchBar.query}"
28
+ @keyup=${(e) => this.onSearchBarKeyUp(e)}
29
+ @focus=${() => {
30
+ this.searchBar.mobileMenuOpen = true;
31
+ this.searchBar.displayFacets = false;
32
+ }}>
33
+ </div>
34
+ </div>
35
+ ${this.renderMobileSearchBarButtons()}
36
+ </div>
37
+ ${this.searchBar.displayFacets ? this.searchBar.renderFacetsActions() : this.selectedFacetsManager.render()}
38
+ ${this.searchBar.displayFacets ? this.searchBar.renderMobileFacets() : this.suggestManager.render()}
39
+ ${this.searchBar.isMobileMenuOpen() || this.searchBar.displayFacets ? html `
40
+ <ft-button class="ft-search-bar--launch-search"
41
+ part="launch-search-in-panel"
42
+ icon="search"
43
+ @click=${this.searchBar.launchSearch}>
44
+ ${this.searchBar.labelResolver.resolve("searchButton")}
45
+ </ft-button>
46
+ ` : nothing}
47
+ </div>
48
+ `;
49
+ }
50
+ renderMobileSearchBarButtons() {
51
+ const displayClearButton = this.searchBar.query || (this.searchBar.isMobileMenuOpen() && !this.searchBar.forceMobileMenuOpen);
52
+ return html `
53
+ <div class="ft-search-bar--actions" part="search-bar-actions">
54
+ ${displayClearButton ? html `
55
+ <ft-button class="ft-search-bar--clear-query"
56
+ part="clear-query"
57
+ icon="close"
58
+ round
59
+ label="${this.searchBar.labelResolver.resolve("clearInputButton")}"
60
+ tooltipPosition="left"
61
+ @click=${() => {
62
+ this.searchBar.setQuery("");
63
+ this.searchBar.mobileMenuOpen = false;
64
+ this.searchBar.displayFacets = false;
65
+ }}
66
+ ></ft-button>
67
+ <div class="ft-search-bar--separator"></div>
68
+ ` : nothing}
69
+ <ft-button class="ft-search-bar--launch-search"
70
+ part="launch-search-in-bar"
71
+ icon="search"
72
+ round
73
+ label="${this.searchBar.labelResolver.resolve("searchButton")}"
74
+ tooltipPosition="left"
75
+ @click=${() => { var _a; return this.searchBar.isMobileMenuOpen() ? this.searchBar.launchSearch() : (_a = this.searchBar.input) === null || _a === void 0 ? void 0 : _a.focus(); }}
76
+ ></ft-button>
77
+ </div>
78
+ `;
79
+ }
80
+ onSearchBarKeyUp(e) {
81
+ const input = e.composedPath()[0];
82
+ this.searchBar.query = input.value;
83
+ if (e.key === "Enter") {
84
+ this.searchBar.launchSearch();
85
+ }
86
+ }
87
+ }
88
+ //language=css
89
+ MobileSearchBarManager.styles = css `
90
+
91
+ `;
92
+ //# sourceMappingURL=MobileSearchBarManager.js.map
@@ -0,0 +1,20 @@
1
+ import type { FtSearchBar } from "../ft-search-bar";
2
+ export declare class SuggestManager {
3
+ private searchBar;
4
+ private updateDebouncer;
5
+ constructor(searchBar: FtSearchBar, debounceTime?: number);
6
+ static styles: import("lit").CSSResult;
7
+ render(): import("lit-html").TemplateResult<1>;
8
+ update(): Promise<void>;
9
+ private onSuggestKeyDown;
10
+ private onSuggestKeyUp;
11
+ private onSuggestClick;
12
+ private onSuggestSelected;
13
+ private removeRecentSearch;
14
+ private getIcon;
15
+ private getFocusedSuggestionElement;
16
+ private getLastSuggestionElement;
17
+ private getFirstSuggestionElement;
18
+ focusFirstSuggestion(): void;
19
+ }
20
+ //# sourceMappingURL=SuggestManager.d.ts.map
@@ -0,0 +1,215 @@
1
+ import { css, html } from "lit";
2
+ import { repeat } from "lit/directives/repeat.js";
3
+ import { FtIcons, FtIconVariants, resolveFileFormatIcon } from "@fluid-topics/ft-icon";
4
+ import { Debouncer } from "@fluid-topics/ft-wc-utils";
5
+ import { FtSearchBarCssVariables } from "../ft-search-bar.css";
6
+ export class SuggestManager {
7
+ constructor(searchBar, debounceTime = 300) {
8
+ this.searchBar = searchBar;
9
+ this.updateDebouncer = new Debouncer(debounceTime);
10
+ }
11
+ render() {
12
+ const filteredRecentSearches = this.searchBar.recentSearches.filter(q => q.toLowerCase().includes(this.searchBar.query.toLowerCase()));
13
+ const shouldDisplaySuggestions = this.searchBar.suggestions.length > 0 || filteredRecentSearches.length > 0;
14
+ return html `
15
+ <div class="ft-search-bar--suggestions ${shouldDisplaySuggestions ? "ft-search-bar--suggestions-not-empty" : ""}"
16
+ part="suggestions-container"
17
+ @keydown=${(e) => this.onSuggestKeyDown(e)}>
18
+ ${repeat(filteredRecentSearches.slice(0, 5), query => query, query => html `
19
+ <a href="${this.searchBar.searchRequestSerializer({
20
+ ...this.searchBar.request,
21
+ query: query
22
+ })}"
23
+ part="suggestions"
24
+ class="ft-search-bar--suggestion ft-search-bar--recent-search"
25
+ @keyup=${(e) => this.onSuggestKeyUp(e, query)}
26
+ @click=${(e) => this.onSuggestClick(e, query)}>
27
+ <ft-ripple></ft-ripple>
28
+ <ft-icon variant="material" part="suggestion-icon">history</ft-icon>
29
+ <ft-typography variant="body1">${query}</ft-typography>
30
+ <ft-button icon="close"
31
+ round
32
+ part="remove-suggestion"
33
+ ?dense=${!this.searchBar.isMobile}
34
+ label="${this.searchBar.labelResolver.resolve("removeRecentSearch")}"
35
+ tooltipPosition="left"
36
+ @click=${(e) => this.removeRecentSearch(e, query)}></ft-button>
37
+ </a>
38
+ `)}
39
+ ${repeat(this.searchBar.suggestions, suggest => suggest.value, suggest => html `
40
+ <a href="${this.searchBar.searchRequestSerializer({
41
+ ...this.searchBar.request,
42
+ query: suggest.value
43
+ })}"
44
+ part="suggestions"
45
+ class="ft-search-bar--suggestion"
46
+ @keyup=${(e) => this.onSuggestKeyUp(e, suggest.value)}
47
+ @click=${(e) => this.onSuggestClick(e, suggest.value)}>
48
+ <ft-ripple></ft-ripple>
49
+ ${this.getIcon(suggest)}
50
+ <ft-typography variant="body1">${suggest.value}</ft-typography>
51
+ </a>
52
+ `)}
53
+ </div>
54
+ `;
55
+ }
56
+ update() {
57
+ return new Promise((accept, reject) => {
58
+ this.updateDebouncer.run(async () => {
59
+ this.searchBar.suggestions = this.searchBar.api && this.searchBar.query.length > 2
60
+ ? await this.searchBar.api.getSuggestions(this.searchBar.suggestRequest).then(r => r.suggestions).catch(() => [])
61
+ : [];
62
+ accept();
63
+ });
64
+ });
65
+ }
66
+ onSuggestKeyDown(e) {
67
+ var _a, _b, _c, _d, _e, _f;
68
+ switch (e.key) {
69
+ case "ArrowUp":
70
+ (_c = ((_b = (_a = this.getFocusedSuggestionElement()) === null || _a === void 0 ? void 0 : _a.previousElementSibling) !== null && _b !== void 0 ? _b : this.getLastSuggestionElement())) === null || _c === void 0 ? void 0 : _c.focus();
71
+ e.preventDefault();
72
+ e.stopPropagation();
73
+ break;
74
+ case "ArrowDown":
75
+ (_f = ((_e = (_d = this.getFocusedSuggestionElement()) === null || _d === void 0 ? void 0 : _d.nextElementSibling) !== null && _e !== void 0 ? _e : this.getFirstSuggestionElement())) === null || _f === void 0 ? void 0 : _f.focus();
76
+ e.preventDefault();
77
+ e.stopPropagation();
78
+ break;
79
+ }
80
+ }
81
+ onSuggestKeyUp(e, suggest) {
82
+ if (e.key === "Enter" || e.key === " ") {
83
+ this.onSuggestSelected(e, suggest);
84
+ }
85
+ }
86
+ onSuggestClick(e, suggest) {
87
+ if (!e.ctrlKey && !e.metaKey) {
88
+ this.onSuggestSelected(e, suggest);
89
+ }
90
+ }
91
+ onSuggestSelected(e, suggest) {
92
+ e.preventDefault();
93
+ this.searchBar.setQuery(suggest);
94
+ this.searchBar.launchSearch();
95
+ }
96
+ removeRecentSearch(e, query) {
97
+ var _a, _b;
98
+ e.preventDefault();
99
+ e.stopPropagation();
100
+ let currentFocuseElement = e.target.closest(".ft-search-bar--suggestion");
101
+ const thingToFocus = (_b = (_a = currentFocuseElement === null || currentFocuseElement === void 0 ? void 0 : currentFocuseElement.previousElementSibling) !== null && _a !== void 0 ? _a : currentFocuseElement === null || currentFocuseElement === void 0 ? void 0 : currentFocuseElement.nextElementSibling) !== null && _b !== void 0 ? _b : this.searchBar.input;
102
+ thingToFocus === null || thingToFocus === void 0 ? void 0 : thingToFocus.focus();
103
+ this.searchBar.recentSearches = this.searchBar.recentSearches.filter(q => q.toLowerCase() !== query.toLowerCase());
104
+ this.searchBar.saveRecentSearches();
105
+ }
106
+ getIcon(suggest) {
107
+ const iconVariant = suggest.type === "DOCUMENT" ? FtIconVariants.file_format : FtIconVariants.fluid_topics;
108
+ let icon;
109
+ switch (suggest.type) {
110
+ case "MAP":
111
+ icon = suggest.editorialType === "BOOK" ? FtIcons.BOOK : FtIcons.ARTICLE;
112
+ break;
113
+ case "DOCUMENT":
114
+ icon = resolveFileFormatIcon(suggest.mimeType, suggest.filenameExtension);
115
+ break;
116
+ case "TOPIC":
117
+ icon = FtIcons.TOPICS;
118
+ break;
119
+ }
120
+ return html `
121
+ <ft-icon variant="${iconVariant}" part="suggestion-icon">
122
+ ${icon}
123
+ </ft-icon>
124
+ `;
125
+ }
126
+ getFocusedSuggestionElement() {
127
+ return this.searchBar.querySelector(".ft-search-bar--suggestion:focus-within");
128
+ }
129
+ getLastSuggestionElement() {
130
+ let suggestions = this.searchBar.querySelectorAll(".ft-search-bar--suggestion");
131
+ return suggestions.length > 0 ? suggestions[suggestions.length - 1] : null;
132
+ }
133
+ getFirstSuggestionElement() {
134
+ return this.searchBar.querySelector(".ft-search-bar--suggestion");
135
+ }
136
+ focusFirstSuggestion() {
137
+ var _a;
138
+ (_a = this.getFirstSuggestionElement()) === null || _a === void 0 ? void 0 : _a.focus();
139
+ }
140
+ }
141
+ //language=css
142
+ SuggestManager.styles = css `
143
+ .ft-search-bar--mobile .ft-search-bar--suggestions {
144
+ flex-grow: 1;
145
+ flex-shrink: 1;
146
+ overflow-y: auto;
147
+ height: 0;
148
+ }
149
+
150
+ .ft-search-bar--mobile-menu-open .ft-search-bar--suggestions {
151
+ border-top: 1px solid ${FtSearchBarCssVariables.colorOutline};
152
+ }
153
+
154
+ .ft-search-bar--mobile-menu-open .ft-search-bar--suggestions {
155
+ height: initial;
156
+ }
157
+
158
+ .ft-search-bar--floating-panel,
159
+ .ft-search-bar--desktop .ft-search-bar--suggestions {
160
+ position: absolute;
161
+ z-index: ${FtSearchBarCssVariables.floatingZIndex};
162
+ top: 100%;
163
+ left: -1px;
164
+ right: -1px;
165
+ display: none;
166
+ background: ${FtSearchBarCssVariables.colorSurface};
167
+ border: 1px solid ${FtSearchBarCssVariables.colorOutline};
168
+ border-radius: 0 0 ${FtSearchBarCssVariables.borderRadius} ${FtSearchBarCssVariables.borderRadius};
169
+ box-shadow: ${FtSearchBarCssVariables.elevation02};
170
+ outline: none;
171
+ }
172
+
173
+ .ft-search-bar--desktop .ft-search-bar--suggestions {
174
+ top: calc(100% + 2px);
175
+ }
176
+
177
+ .ft-search-bar--input-container:focus-within .ft-search-bar--suggestions-not-empty {
178
+ display: block;
179
+ }
180
+
181
+ .ft-search-bar--suggestion {
182
+ text-decoration: none;
183
+ position: relative;
184
+ display: flex;
185
+ align-items: center;
186
+ padding: 8px;
187
+ gap: 8px;
188
+ cursor: pointer;
189
+ color: ${FtSearchBarCssVariables.colorOnSurface};
190
+ min-height: 52px;
191
+ }
192
+
193
+ .ft-search-bar--suggestion > *:not(ft-ripple) {
194
+ position: relative;
195
+ }
196
+
197
+ .ft-search-bar--desktop .ft-search-bar--suggestion {
198
+ min-height: 44px;
199
+ }
200
+
201
+ .ft-search-bar--suggestion:focus {
202
+ outline: none;
203
+ }
204
+
205
+ .ft-search-bar--recent-search + .ft-search-bar--suggestion:not(.ft-search-bar--recent-search) {
206
+ border-top: 1px solid ${FtSearchBarCssVariables.colorOutline};
207
+ }
208
+
209
+ .ft-search-bar--suggestion ft-typography {
210
+ display: block;
211
+ flex-grow: 1;
212
+ flex-shrink: 1;
213
+ }
214
+ `;
215
+ //# sourceMappingURL=SuggestManager.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluid-topics/ft-search-bar",
3
- "version": "0.3.0",
3
+ "version": "0.3.3",
4
4
  "description": "Search bar component using Fluid Topics public API",
5
5
  "keywords": [
6
6
  "Lit"
@@ -11,26 +11,26 @@
11
11
  "web": "build/ft-search-bar.min.js",
12
12
  "typings": "build/index",
13
13
  "files": [
14
- "build/*.ts",
15
- "build/*.js"
14
+ "build/**/*.ts",
15
+ "build/**/*.js"
16
16
  ],
17
17
  "repository": {
18
18
  "type": "git",
19
19
  "url": "ssh://git@scm.mrs.antidot.net:2222/fluidtopics/ft-web-components.git"
20
20
  },
21
21
  "dependencies": {
22
- "@fluid-topics/ft-accordion": "^0.3.0",
23
- "@fluid-topics/ft-button": "^0.3.0",
24
- "@fluid-topics/ft-chip": "^0.3.0",
25
- "@fluid-topics/ft-filter": "^0.3.0",
26
- "@fluid-topics/ft-icon": "^0.3.0",
27
- "@fluid-topics/ft-select": "^0.3.0",
28
- "@fluid-topics/ft-size-watcher": "^0.3.0",
29
- "@fluid-topics/ft-skeleton": "^0.3.0",
30
- "@fluid-topics/ft-snap-scroll": "^0.3.0",
31
- "@fluid-topics/ft-tooltip": "^0.3.0",
32
- "@fluid-topics/ft-typography": "^0.3.0",
33
- "@fluid-topics/ft-wc-utils": "^0.3.0",
22
+ "@fluid-topics/ft-accordion": "0.3.3",
23
+ "@fluid-topics/ft-button": "0.3.3",
24
+ "@fluid-topics/ft-chip": "0.3.3",
25
+ "@fluid-topics/ft-filter": "0.3.3",
26
+ "@fluid-topics/ft-icon": "0.3.3",
27
+ "@fluid-topics/ft-select": "0.3.3",
28
+ "@fluid-topics/ft-size-watcher": "0.3.3",
29
+ "@fluid-topics/ft-skeleton": "0.3.3",
30
+ "@fluid-topics/ft-snap-scroll": "0.3.3",
31
+ "@fluid-topics/ft-tooltip": "0.3.3",
32
+ "@fluid-topics/ft-typography": "0.3.3",
33
+ "@fluid-topics/ft-wc-utils": "0.3.3",
34
34
  "lit": "2.2.8"
35
35
  },
36
36
  "devDependencies": {
@@ -39,5 +39,5 @@
39
39
  "peerDependencies": {
40
40
  "@fluid-topics/public-api": "1.0.18"
41
41
  },
42
- "gitHead": "2019aceb4a578402211f951ec3d68dbc0acf25c7"
42
+ "gitHead": "b8846f1a72db01834c7217897043ef8cbf7d06fb"
43
43
  }