@telia-ace/knowledge-widget-components-search 1.0.1

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/lib/utils.js ADDED
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.filterItems = exports.match = void 0;
4
+ var widget_utilities_1 = require("@telia-ace/widget-utilities");
5
+ var match = function (title, phrase) {
6
+ if (!phrase || !title) {
7
+ return true;
8
+ }
9
+ return !!(title.toLowerCase().indexOf(phrase.toLowerCase()) > -1);
10
+ };
11
+ exports.match = match;
12
+ var filterItems = function (items, type, phrase) {
13
+ if (items === void 0) { items = []; }
14
+ if (!phrase) {
15
+ return items;
16
+ }
17
+ var cloned = (0, widget_utilities_1.deepClone)(items);
18
+ if (type === 'tag') {
19
+ return cloned.filter(function (i) { return (0, exports.match)(i.title, phrase); });
20
+ }
21
+ var matchTrail = buildMatchTrail(cloned, phrase);
22
+ var filtered = recursiveFilter(cloned, function (c) { return matchTrail.indexOf(c.id) > -1; });
23
+ return filtered;
24
+ };
25
+ exports.filterItems = filterItems;
26
+ var recursiveFilter = function (items, fn) {
27
+ return items.filter(function (i) {
28
+ if (i.items && i.items.length) {
29
+ i.items = recursiveFilter(i.items, fn);
30
+ }
31
+ return fn(i);
32
+ });
33
+ };
34
+ var buildMatchTrail = function (categories, phrase) {
35
+ var flattened = flatten(categories);
36
+ var matching = flattened.filter(function (c) { return (0, exports.match)(c.title, phrase); }).map(function (c) { return c.id; });
37
+ var res = [];
38
+ matching.forEach(function (id) {
39
+ var trail = (0, widget_utilities_1.categoryTrail)(id, categories);
40
+ res = res.concat(trail);
41
+ });
42
+ return res;
43
+ };
44
+ var flatten = function (categories) {
45
+ var result = [];
46
+ categories.forEach(function (category) {
47
+ result.push(category);
48
+ if (Array.isArray(category.items)) {
49
+ result = result.concat(flatten(category.items));
50
+ }
51
+ });
52
+ return result;
53
+ };
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ declare type Props = {
3
+ inputHasFocus: boolean;
4
+ searchContainerRef: HTMLElement | null;
5
+ showGuideCategory: boolean;
6
+ showTag: boolean;
7
+ position: 'inside' | 'below';
8
+ };
9
+ declare const FilterBadges: React.FC<Props>;
10
+ export default FilterBadges;
@@ -0,0 +1,210 @@
1
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
2
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
3
+ return cooked;
4
+ };
5
+ var __assign = (this && this.__assign) || function () {
6
+ __assign = Object.assign || function(t) {
7
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
8
+ s = arguments[i];
9
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
10
+ t[p] = s[p];
11
+ }
12
+ return t;
13
+ };
14
+ return __assign.apply(this, arguments);
15
+ };
16
+ var __rest = (this && this.__rest) || function (s, e) {
17
+ var t = {};
18
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
19
+ t[p] = s[p];
20
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
21
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
22
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
23
+ t[p[i]] = s[p[i]];
24
+ }
25
+ return t;
26
+ };
27
+ var __read = (this && this.__read) || function (o, n) {
28
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
29
+ if (!m) return o;
30
+ var i = m.call(o), r, ar = [], e;
31
+ try {
32
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
33
+ }
34
+ catch (error) { e = { error: error }; }
35
+ finally {
36
+ try {
37
+ if (r && !r.done && (m = i["return"])) m.call(i);
38
+ }
39
+ finally { if (e) throw e.error; }
40
+ }
41
+ return ar;
42
+ };
43
+ import { borderTabStyle, Link, SymbolBadge, Text, Tooltip, useDispatch, useEventListener, useKeyPress, useProperties, useRouteData, } from '@telia-ace/knowledge-widget-ui';
44
+ import { appendClassNames } from '@telia-ace/widget-utilities';
45
+ import React, { useCallback, useRef, useState } from 'react';
46
+ import styled, { css } from 'styled-components';
47
+ var FilterBadge = function (_a) {
48
+ var text = _a.text, className = _a.className, forceFocusStyle = _a.forceFocusStyle, filterType = _a.filterType, handleClick = _a.handleClick, _b = _a.deleteAriaLabel, deleteAriaLabel = _b === void 0 ? '' : _b, p = __rest(_a, ["text", "className", "forceFocusStyle", "filterType", "handleClick", "deleteAriaLabel"]);
49
+ var ref = useRef();
50
+ return (React.createElement(Text, { className: appendClassNames(className, 'humany-filter-badge'), onKeyDown: function (e) {
51
+ if (e.key === 'Enter') {
52
+ handleClick(e, filterType);
53
+ }
54
+ } },
55
+ text,
56
+ React.createElement(Link, __assign({}, p, { ref: ref, tabIndex: 0, role: "button", "aria-label": deleteAriaLabel.replace('{{item}}', text), onClick: function (e) { return handleClick(e, filterType); } }),
57
+ React.createElement(SymbolBadge, { size: 13, symbol: { type: 'Svg', content: 'close' } }))));
58
+ };
59
+ var FilterBadges = function (_a) {
60
+ var inputHasFocus = _a.inputHasFocus, searchContainerRef = _a.searchContainerRef, showTag = _a.showTag, showGuideCategory = _a.showGuideCategory, position = _a.position;
61
+ var _b = useProperties(), _c = _b.activeFilterBadges, activeFilterBadges = _c === void 0 ? {} : _c, _d = _b.deleteFilterBadgeAriaLabel, deleteFilterBadgeAriaLabel = _d === void 0 ? '' : _d;
62
+ var dispatch = useDispatch();
63
+ var _e = useRouteData(), name = _e.name, params = _e.params;
64
+ var _f = __read(useState(false), 2), isNavigatingWithKeyBoard = _f[0], setIsNavigatingWithKeyboard = _f[1];
65
+ var onKeyDown = useCallback(function (event) {
66
+ var key = event.key;
67
+ if (['ArrowLeft', 'ArrowRight'].indexOf(key) === -1) {
68
+ setIsNavigatingWithKeyboard(false);
69
+ }
70
+ }, []);
71
+ useEventListener('keydown', onKeyDown, window);
72
+ useEventListener('click', onKeyDown, window);
73
+ var guideCategory = activeFilterBadges.guideCategory, tag = activeFilterBadges.tag, tooltip = activeFilterBadges.tooltip;
74
+ var getFocusedFilterBadge = function (container) {
75
+ var badges = container.querySelectorAll('.humany-filter-badge');
76
+ return {
77
+ badges: badges,
78
+ index: Array.from(badges).findIndex(function (e) { return document.activeElement === e; }),
79
+ };
80
+ };
81
+ var handleFilterBadgeClick = function (event, filterType) {
82
+ event.preventDefault();
83
+ dispatch('quick-filter:remove', { types: [filterType] });
84
+ };
85
+ var keyboardNavigation = function (direction, inputElem) {
86
+ if (!searchContainerRef) {
87
+ return;
88
+ }
89
+ var _a = getFocusedFilterBadge(searchContainerRef), badges = _a.badges, currentFocusedIndex = _a.index;
90
+ if (badges.length) {
91
+ var toFocus = null;
92
+ if (direction === 'left') {
93
+ if (currentFocusedIndex === -1) {
94
+ // if no badge is focused and direction is left
95
+ // focus last badge
96
+ toFocus = badges.item(badges.length - 1);
97
+ }
98
+ else if (currentFocusedIndex > 0) {
99
+ // if there are more badges to the left, go one step back
100
+ // do nothing if already focusing the most left badge
101
+ toFocus = badges.item(currentFocusedIndex - 1);
102
+ }
103
+ }
104
+ else if (direction === 'right') {
105
+ if (currentFocusedIndex === badges.length - 1) {
106
+ // if currently focusing the last badge, move focus to search input
107
+ inputElem && inputElem.focus();
108
+ }
109
+ else if (badges.item(currentFocusedIndex + 1)) {
110
+ toFocus = badges.item(currentFocusedIndex + 1);
111
+ }
112
+ }
113
+ if (toFocus) {
114
+ toFocus.focus();
115
+ setIsNavigatingWithKeyboard(true);
116
+ }
117
+ }
118
+ };
119
+ useKeyPress('ArrowLeft', useCallback(function () {
120
+ if (!searchContainerRef) {
121
+ return;
122
+ }
123
+ var focusedBadgeIndex = getFocusedFilterBadge(searchContainerRef).index;
124
+ if (inputHasFocus || focusedBadgeIndex > -1) {
125
+ var inputElem = searchContainerRef.querySelector('[data-type="search"]');
126
+ var isAtBeginningOfInput = inputElem && inputElem.selectionStart !== null && inputElem.selectionStart <= 0;
127
+ var isFocusingAFilterBadge = focusedBadgeIndex > -1;
128
+ if (isAtBeginningOfInput || isFocusingAFilterBadge) {
129
+ keyboardNavigation('left', inputElem);
130
+ }
131
+ }
132
+ }, [inputHasFocus, searchContainerRef]));
133
+ useKeyPress('ArrowRight', useCallback(function () {
134
+ if (!searchContainerRef) {
135
+ return;
136
+ }
137
+ var focusedBadgeIndex = getFocusedFilterBadge(searchContainerRef).index;
138
+ if (focusedBadgeIndex > -1) {
139
+ var inputElem = searchContainerRef.querySelector('[data-type="search"]');
140
+ var isFocusingAFilterBadge = focusedBadgeIndex > -1;
141
+ if (isFocusingAFilterBadge) {
142
+ keyboardNavigation('right', inputElem);
143
+ }
144
+ }
145
+ }, [searchContainerRef]));
146
+ useKeyPress('Backspace', useCallback(function (event) {
147
+ if (!searchContainerRef) {
148
+ return;
149
+ }
150
+ var filtersToRemove = [];
151
+ var focusedBadgeIndex = getFocusedFilterBadge(searchContainerRef).index;
152
+ var inputElem = searchContainerRef.querySelector('[data-type="search"]');
153
+ var isFocusingAFilterBadge = focusedBadgeIndex > -1;
154
+ if (isFocusingAFilterBadge) {
155
+ if (focusedBadgeIndex === 0) {
156
+ if (showGuideCategory) {
157
+ filtersToRemove = ['guideCategory'];
158
+ }
159
+ else if (showTag) {
160
+ filtersToRemove = ['tag'];
161
+ }
162
+ }
163
+ else if (focusedBadgeIndex === 1) {
164
+ filtersToRemove = ['tag'];
165
+ }
166
+ }
167
+ else {
168
+ var isAtBeginningOfInput = inputElem &&
169
+ inputElem.selectionStart !== null &&
170
+ inputElem.selectionStart <= 0;
171
+ if (isAtBeginningOfInput) {
172
+ if (activeFilterBadges === null || activeFilterBadges === void 0 ? void 0 : activeFilterBadges.tag) {
173
+ filtersToRemove = ['tag'];
174
+ }
175
+ else if (activeFilterBadges === null || activeFilterBadges === void 0 ? void 0 : activeFilterBadges.guideCategory) {
176
+ filtersToRemove = ['guideCategory'];
177
+ }
178
+ }
179
+ }
180
+ if (filtersToRemove.length > 0) {
181
+ event.preventDefault();
182
+ dispatch('quick-filter:remove', { types: filtersToRemove });
183
+ }
184
+ }, [searchContainerRef, activeFilterBadges, showTag, showGuideCategory]));
185
+ var renderBadge = useCallback(function (type) {
186
+ if (type === 'guideCategory' && guideCategory && showGuideCategory) {
187
+ return (React.createElement(StyledFilterBadge, { text: "@".concat(guideCategory.title), routeName: name, filterType: "guideCategory", handleClick: handleFilterBadgeClick, forceFocusStyle: isNavigatingWithKeyBoard, deleteAriaLabel: deleteFilterBadgeAriaLabel, params: __assign(__assign({}, params), { guideCategory: undefined }) }));
188
+ }
189
+ if (type === 'tag' && tag && showTag) {
190
+ return (React.createElement(StyledFilterBadge, { className: "humany-filter-badge", text: "#".concat(tag.title), routeName: name, filterType: "tag", handleClick: handleFilterBadgeClick, forceFocusStyle: isNavigatingWithKeyBoard, deleteAriaLabel: deleteFilterBadgeAriaLabel, params: __assign(__assign({}, params), { tag: undefined }) }));
191
+ }
192
+ return null;
193
+ }, [guideCategory, tag, name, params, showGuideCategory, showTag, isNavigatingWithKeyBoard]);
194
+ if (!guideCategory && !tag) {
195
+ return null;
196
+ }
197
+ return (React.createElement(Wrapper, { className: "humany-filter-badges", position: position },
198
+ guideCategory && tooltip ? (React.createElement(Tooltip, { content: React.createElement(React.Fragment, null, tooltip), sticky: false }, renderBadge('guideCategory'))) : (renderBadge('guideCategory')),
199
+ tag && renderBadge('tag')));
200
+ };
201
+ export default FilterBadges;
202
+ var Wrapper = styled.div(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n\n ", "\n"], ["\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n\n ", "\n"])), function (p) {
203
+ return p.position === 'inside'
204
+ ? css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n &:not(:first-child) {\n margin: 0 0 0 ", ";\n }\n "], ["\n &:not(:first-child) {\n margin: 0 0 0 ", ";\n }\n "])), function (p) { var _a; return (_a = p.theme.sizes) === null || _a === void 0 ? void 0 : _a.normal; }) : css(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n margin: ", " 0 0 0;\n span:first-child {\n margin-left: 0;\n }\n "], ["\n margin: ", " 0 0 0;\n span:first-child {\n margin-left: 0;\n }\n "])), function (p) { var _a; return (_a = p.theme.sizes) === null || _a === void 0 ? void 0 : _a.small; });
205
+ });
206
+ var StyledFilterBadge = styled(FilterBadge)(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n display: flex;\n align-items: center;\n padding: ", ";\n background-color: ", ";\n border-radius: ", ";\n font-weight: 300;\n font-size: ", ";\n font-style: italic;\n color: #ffffff;\n text-decoration: none;\n white-space: nowrap;\n\n margin: calc(", " / 2);\n\n &:focus-within {\n ", ";\n a {\n outline: none;\n }\n }\n\n svg {\n width: 17px;\n height: 11px;\n margin: 1px 0 0 ", ";\n path {\n stroke: #ffffff;\n stroke-width: 2px;\n }\n order: 1;\n }\n"], ["\n display: flex;\n align-items: center;\n padding: ", ";\n background-color: ", ";\n border-radius: ", ";\n font-weight: 300;\n font-size: ", ";\n font-style: italic;\n color: #ffffff;\n text-decoration: none;\n white-space: nowrap;\n\n margin: calc(", " / 2);\n\n &:focus-within {\n ", ";\n a {\n outline: none;\n }\n }\n\n svg {\n width: 17px;\n height: 11px;\n margin: 1px 0 0 ", ";\n path {\n stroke: #ffffff;\n stroke-width: 2px;\n }\n order: 1;\n }\n"])), function (p) { var _a, _b; return "".concat((_a = p.theme.sizes) === null || _a === void 0 ? void 0 : _a.small, " calc(").concat((_b = p.theme.sizes) === null || _b === void 0 ? void 0 : _b.normal, "/2) "); }, function (p) { var _a; return (_a = p.theme.colors) === null || _a === void 0 ? void 0 : _a.primary; }, function (p) { return p.theme.borderRadius; }, function (p) { var _a; return (_a = p.theme.fonts) === null || _a === void 0 ? void 0 : _a.normal; }, function (p) { var _a; return (_a = p.theme.sizes) === null || _a === void 0 ? void 0 : _a.small; }, function (p) {
207
+ var _a;
208
+ return (((_a = p.theme.accessibility) === null || _a === void 0 ? void 0 : _a.isTabbing) || p.forceFocusStyle) && css(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n ", "\n background-color: transparent;\n\n svg {\n path {\n stroke: ", ";\n }\n }\n "], ["\n ", "\n background-color: transparent;\n\n svg {\n path {\n stroke: ", ";\n }\n }\n "])), borderTabStyle, function (p) { var _a; return (_a = p.theme.colors) === null || _a === void 0 ? void 0 : _a.primary; });
209
+ }, function (p) { var _a; return (_a = p.theme.sizes) === null || _a === void 0 ? void 0 : _a.small; });
210
+ var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5;
@@ -0,0 +1,2 @@
1
+ import SearchComponent from './search-component';
2
+ export default SearchComponent;
@@ -0,0 +1,2 @@
1
+ import SearchComponent from './search-component';
2
+ export default SearchComponent;
@@ -0,0 +1,17 @@
1
+ import { Category, Tag } from '@telia-ace/knowledge-widget-core';
2
+ import React from 'react';
3
+ declare type Props = {
4
+ filterPhrase: string;
5
+ items: Category[] | Tag[];
6
+ filterType: 'guideCategory' | 'tag';
7
+ searchContainer: HTMLElement | null;
8
+ filterContainer: HTMLElement | null;
9
+ inputHasFocus: boolean;
10
+ };
11
+ export declare const getFocusedIndex: (elem: HTMLElement) => {
12
+ anchors: HTMLAnchorElement[];
13
+ focusedIndex: number;
14
+ };
15
+ export declare const focusInput: (searchContainerRef: HTMLElement | null) => void;
16
+ declare const QuickFilterItemList: React.FC<Props>;
17
+ export default QuickFilterItemList;
@@ -0,0 +1,200 @@
1
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
2
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
3
+ return cooked;
4
+ };
5
+ var __assign = (this && this.__assign) || function () {
6
+ __assign = Object.assign || function(t) {
7
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
8
+ s = arguments[i];
9
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
10
+ t[p] = s[p];
11
+ }
12
+ return t;
13
+ };
14
+ return __assign.apply(this, arguments);
15
+ };
16
+ var __read = (this && this.__read) || function (o, n) {
17
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
18
+ if (!m) return o;
19
+ var i = m.call(o), r, ar = [], e;
20
+ try {
21
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
22
+ }
23
+ catch (error) { e = { error: error }; }
24
+ finally {
25
+ try {
26
+ if (r && !r.done && (m = i["return"])) m.call(i);
27
+ }
28
+ finally { if (e) throw e.error; }
29
+ }
30
+ return ar;
31
+ };
32
+ import { ItemTree, Link, Text, useDispatch, useEventListener, useProperties, } from '@telia-ace/knowledge-widget-ui';
33
+ import React, { useCallback, useEffect, useState } from 'react';
34
+ import styled, { css } from 'styled-components';
35
+ import { filterItems, match } from './utils';
36
+ export var getFocusedIndex = function (elem) {
37
+ var anchors = Array.from((elem === null || elem === void 0 ? void 0 : elem.getElementsByTagName('A')) || []).filter(function (a) { return a.getAttribute('disabled') === null; });
38
+ return {
39
+ anchors: anchors,
40
+ focusedIndex: anchors.findIndex(function (e) { return document.activeElement === e; }),
41
+ };
42
+ };
43
+ var getInputElem = function (searchContainerRef) {
44
+ return searchContainerRef
45
+ ? searchContainerRef.querySelector('[data-type="search"], input[type="search"]')
46
+ : null;
47
+ };
48
+ export var focusInput = function (searchContainerRef) {
49
+ if (!searchContainerRef) {
50
+ return;
51
+ }
52
+ var inputElem = getInputElem(searchContainerRef);
53
+ if (inputElem) {
54
+ inputElem.focus();
55
+ }
56
+ };
57
+ var QuickFilterItemList = function (_a) {
58
+ var filterPhrase = _a.filterPhrase, rawItems = _a.items, filterType = _a.filterType, filterContainer = _a.filterContainer, searchContainer = _a.searchContainer, inputHasFocus = _a.inputHasFocus;
59
+ var _b = __read(useState(rawItems || []), 2), items = _b[0], setItems = _b[1];
60
+ var _c = __read(useState(null), 2), first = _c[0], setFirst = _c[1];
61
+ var dispatch = useDispatch();
62
+ var _d = useProperties(), activeFilterBadges = _d.activeFilterBadges, quickFilters = _d.quickFilters;
63
+ var autoSelect = (typeof quickFilters === 'object' && !!quickFilters.autoSelect) ||
64
+ (typeof quickFilters === 'boolean' && !!quickFilters);
65
+ useEffect(function () {
66
+ setItems(filterItems(rawItems, filterType, filterPhrase));
67
+ }, [filterPhrase, filterType, rawItems]);
68
+ useEffect(function () {
69
+ var _a;
70
+ if (filterContainer) {
71
+ var anchors = getFocusedIndex(filterContainer).anchors;
72
+ var id = (_a = anchors[0]) === null || _a === void 0 ? void 0 : _a.getAttribute('data-id');
73
+ if (id) {
74
+ setFirst(id);
75
+ }
76
+ }
77
+ }, [items, filterContainer]);
78
+ var handleItemClicked = useCallback(function (item, type) {
79
+ var data = {
80
+ category: (activeFilterBadges === null || activeFilterBadges === void 0 ? void 0 : activeFilterBadges.guideCategory)
81
+ ? activeFilterBadges.guideCategory.id
82
+ : undefined,
83
+ tag: (activeFilterBadges === null || activeFilterBadges === void 0 ? void 0 : activeFilterBadges.tag) ? activeFilterBadges.tag.id : undefined,
84
+ };
85
+ if (type === 'guideCategory') {
86
+ data.category = item.id;
87
+ }
88
+ else if (type === 'tag') {
89
+ data.tag = item.id;
90
+ }
91
+ dispatch('quick-filter:add', data);
92
+ }, [activeFilterBadges, dispatch]);
93
+ var buildListProps = function (type) {
94
+ if (type === 'guideCategory') {
95
+ return {
96
+ renderItem: function (item, level) { return (React.createElement(StyledLink, { autoSelect: autoSelect && inputHasFocus && item.id === first, disabled: !match(item.title, filterPhrase), tabIndex: !match(item.title, filterPhrase) ? -1 : 0, onKeyDown: function (e) {
97
+ if (e.key === 'Enter') {
98
+ handleItemClicked(item, type);
99
+ }
100
+ }, "data-level": level, onClick: function () {
101
+ handleItemClicked(item, type);
102
+ }, "data-id": item.id },
103
+ React.createElement(Title, { title: item.title, phrase: filterPhrase, matches: match(item.title, filterPhrase) }))); },
104
+ };
105
+ }
106
+ return {
107
+ renderLi: true,
108
+ renderItem: function (item) { return (React.createElement(StyledLink, { autoSelect: autoSelect && inputHasFocus && item.id === first, onKeyDown: function (e) {
109
+ if (e.key === 'Enter') {
110
+ handleItemClicked(item, type);
111
+ }
112
+ }, onClick: function () {
113
+ handleItemClicked(item, type);
114
+ }, "data-id": item.id },
115
+ React.createElement(Title, { symbol: "#", title: item.title, phrase: filterPhrase, matches: match(item.title, filterPhrase) }))); },
116
+ };
117
+ };
118
+ useEventListener('keydown', function (e) {
119
+ var _a;
120
+ var key = e.key;
121
+ if (!filterContainer ||
122
+ !(key === 'ArrowDown' || key === 'ArrowUp' || key === 'Enter')) {
123
+ return;
124
+ }
125
+ var _b = getFocusedIndex(filterContainer), anchors = _b.anchors, focusedIndex = _b.focusedIndex;
126
+ if (key === 'Enter') {
127
+ if (inputHasFocus && autoSelect) {
128
+ var id = (_a = anchors[0]) === null || _a === void 0 ? void 0 : _a.getAttribute('data-id');
129
+ if (id) {
130
+ handleItemClicked({ id: id }, filterType);
131
+ }
132
+ }
133
+ return;
134
+ }
135
+ var focusFirst = function () { var _a; return (_a = anchors[0]) === null || _a === void 0 ? void 0 : _a.focus(); };
136
+ var focusLast = function () { var _a; return (_a = anchors[anchors.length - 1]) === null || _a === void 0 ? void 0 : _a.focus(); };
137
+ var focusNext = function () { var _a; return (_a = anchors[focusedIndex + 1]) === null || _a === void 0 ? void 0 : _a.focus(); };
138
+ var focusPrev = function () { var _a; return (_a = anchors[focusedIndex - 1]) === null || _a === void 0 ? void 0 : _a.focus(); };
139
+ if (inputHasFocus) {
140
+ // Input is focused
141
+ e.preventDefault();
142
+ if (key === 'ArrowDown') {
143
+ focusFirst();
144
+ }
145
+ else {
146
+ focusLast();
147
+ }
148
+ }
149
+ else if (focusedIndex > -1) {
150
+ // A quick-filter-item is focused
151
+ e.preventDefault();
152
+ if (key === 'ArrowDown') {
153
+ if (anchors.length > focusedIndex + 1) {
154
+ focusNext();
155
+ }
156
+ else {
157
+ focusInput(searchContainer);
158
+ }
159
+ }
160
+ else {
161
+ if (focusedIndex - 1 < 0) {
162
+ focusInput(searchContainer);
163
+ }
164
+ else {
165
+ focusPrev();
166
+ }
167
+ }
168
+ }
169
+ }, window);
170
+ return (React.createElement(ItemTree, __assign({ tree: items, renderEmpty: false, ulProps: { role: 'listbox' }, liProps: { role: 'option' } }, buildListProps(filterType))));
171
+ };
172
+ export default QuickFilterItemList;
173
+ var Title = function (_a) {
174
+ var title = _a.title, phrase = _a.phrase, matches = _a.matches, _b = _a.symbol, symbol = _b === void 0 ? '' : _b;
175
+ var createTitle = function () {
176
+ if (!matches || !phrase) {
177
+ return [title];
178
+ }
179
+ var index = title.toLowerCase().indexOf(phrase.toLowerCase());
180
+ var start = title.substr(0, index);
181
+ var bold = title.slice(index, index + phrase.length);
182
+ var end = title.substr(index + phrase.length);
183
+ return [start, bold, end];
184
+ };
185
+ var _c = __read(createTitle(), 3), start = _c[0], bold = _c[1], end = _c[2];
186
+ return (React.createElement(Text, null,
187
+ symbol,
188
+ start,
189
+ bold ? React.createElement("strong", null, bold) : null,
190
+ end ? end : null));
191
+ };
192
+ var disabledCss = css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n opacity: 0.5;\n pointer-events: none;\n"], ["\n opacity: 0.5;\n pointer-events: none;\n"])));
193
+ var focused = css(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n background-color: ", ";\n color: #ffffff;\n outline: none;\n\n span:first-child {\n border-color: ", ";\n }\n"], ["\n background-color: ", ";\n color: #ffffff;\n outline: none;\n\n span:first-child {\n border-color: ", ";\n }\n"])), function (p) { var _a; return (_a = p.theme.colors) === null || _a === void 0 ? void 0 : _a.text; }, function (p) { var _a; return (_a = p.theme.colors) === null || _a === void 0 ? void 0 : _a.text; });
194
+ var StyledLink = styled(Link)(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n display: block;\n text-decoration: none;\n font-size: ", ";\n\n ", "\n color: ", ";\n background-color: transparent;\n\n span {\n display: block;\n ", "\n ", "\n }\n\n span:first-child {\n border-color: #e7e7e7;\n }\n\n ", "\n\n ", "\n\n &:hover,\n &:focus {\n ", "\n }\n"], ["\n display: block;\n text-decoration: none;\n font-size: ", ";\n\n ", "\n color: ", ";\n background-color: transparent;\n\n span {\n display: block;\n ", "\n ", "\n }\n\n span:first-child {\n border-color: #e7e7e7;\n }\n\n ", "\n\n ", "\n\n &:hover,\n &:focus {\n ", "\n }\n"])), function (p) { var _a; return (_a = p.theme.fonts) === null || _a === void 0 ? void 0 : _a.normal; }, function (p) { return p.disabled && disabledCss; }, function (p) { var _a; return (_a = p.theme.colors) === null || _a === void 0 ? void 0 : _a.text; }, function (p) {
195
+ var _a, _b, _c, _d;
196
+ return p['data-level']
197
+ ? "padding: calc(".concat((_a = p.theme.sizes) === null || _a === void 0 ? void 0 : _a.normal, " / 2) ").concat((_b = p.theme.sizes) === null || _b === void 0 ? void 0 : _b.normal, ";")
198
+ : "padding: calc(".concat((_c = p.theme.sizes) === null || _c === void 0 ? void 0 : _c.normal, " / 2) ").concat((_d = p.theme.sizes) === null || _d === void 0 ? void 0 : _d.medium, "; ");
199
+ }, function (p) { return p['data-level'] && 'border-left: 2px solid'; }, function (p) { var _a; return p['data-level'] && "padding: 0 calc(".concat((_a = p.theme.sizes) === null || _a === void 0 ? void 0 : _a.medium, " * ").concat(p['data-level'], ");"); }, function (p) { return p.autoSelect && focused; }, focused);
200
+ var templateObject_1, templateObject_2, templateObject_3;
@@ -0,0 +1,8 @@
1
+ /// <reference types="react" />
2
+ declare type Props = {
3
+ phrase: string;
4
+ inputHasFocus: boolean;
5
+ searchContainerRef: HTMLElement | null;
6
+ };
7
+ declare const _default: ({ phrase, inputHasFocus, searchContainerRef }: Props) => JSX.Element | null;
8
+ export default _default;
@@ -0,0 +1,65 @@
1
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
2
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
3
+ return cooked;
4
+ };
5
+ var __read = (this && this.__read) || function (o, n) {
6
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
7
+ if (!m) return o;
8
+ var i = m.call(o), r, ar = [], e;
9
+ try {
10
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
11
+ }
12
+ catch (error) { e = { error: error }; }
13
+ finally {
14
+ try {
15
+ if (r && !r.done && (m = i["return"])) m.call(i);
16
+ }
17
+ finally { if (e) throw e.error; }
18
+ }
19
+ return ar;
20
+ };
21
+ import { contentBox, Loader, useContainer, useProperties, useScroll, } from '@telia-ace/knowledge-widget-ui';
22
+ import { appendClassNames } from '@telia-ace/widget-utilities';
23
+ import React, { useCallback, useRef } from 'react';
24
+ import styled from 'styled-components';
25
+ import QuickFilterItemList, { focusInput, getFocusedIndex } from './quick-filter-item-list';
26
+ export default (function (_a) {
27
+ var _b = _a.phrase, phrase = _b === void 0 ? '' : _b, inputHasFocus = _a.inputHasFocus, searchContainerRef = _a.searchContainerRef;
28
+ var _c = useProperties().quickFilter, quickFilter = _c === void 0 ? {
29
+ open: false,
30
+ loading: false,
31
+ symbol: '',
32
+ type: '',
33
+ items: [],
34
+ } : _c;
35
+ var _d = __read(useScroll(true), 2), css = _d[0], ref = _d[1];
36
+ var container = useContainer();
37
+ var events = container.get('$widget').events;
38
+ var wrapperRef = useRef();
39
+ var setWrapperRef = useCallback(function (node) {
40
+ if (node) {
41
+ node.addEventListener('keydown', function () {
42
+ var listItemFocused = getFocusedIndex(node).focusedIndex > -1;
43
+ if (listItemFocused) {
44
+ events.subscribeOnce('router:changed', function () {
45
+ focusInput(searchContainerRef);
46
+ });
47
+ }
48
+ }, true);
49
+ }
50
+ wrapperRef.current = node;
51
+ return node;
52
+ }, [searchContainerRef]);
53
+ var _e = quickFilter.items, items = _e === void 0 ? [] : _e, symbol = quickFilter.symbol, type = quickFilter.type, open = quickFilter.open, loading = quickFilter.loading;
54
+ if (!open || !symbol) {
55
+ return null;
56
+ }
57
+ var filterPhrase = phrase.slice(phrase.indexOf(symbol) + 1);
58
+ return (React.createElement(Wrapper, { ref: setWrapperRef, "data-loading": loading, className: appendClassNames('humany-quick-filter-dropdown', [type === 'guideCategory', 'humany-quick-filter-guide-categories'], [type === 'tag', 'humany-quick-filter-tags']) },
59
+ React.createElement(Inner, { className: "humany-quick-filter-dropdown-inner", css: css, ref: ref },
60
+ React.createElement(QuickFilterItemList, { filterType: type, items: items, filterPhrase: filterPhrase, filterContainer: ref.current, searchContainer: searchContainerRef, inputHasFocus: inputHasFocus })),
61
+ React.createElement(Loader, { loading: loading })));
62
+ });
63
+ var Wrapper = styled.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n ", ";\n position: absolute;\n top: calc(100% + ", ");\n left: 0;\n right: 0;\n z-index: 1;\n overflow: hidden;\n"], ["\n ", ";\n position: absolute;\n top: calc(100% + ", ");\n left: 0;\n right: 0;\n z-index: 1;\n overflow: hidden;\n"])), contentBox, function (p) { var _a; return (_a = p.theme.sizes) === null || _a === void 0 ? void 0 : _a.normal; });
64
+ var Inner = styled.div(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n max-height: 300px;\n overflow: auto;\n padding: ", " 0;\n ", "\n ul {\n list-style: none;\n padding: 0;\n margin: 0;\n }\n li div {\n ", "\n }\n"], ["\n max-height: 300px;\n overflow: auto;\n padding: ", " 0;\n ", "\n ul {\n list-style: none;\n padding: 0;\n margin: 0;\n }\n li div {\n ", "\n }\n"])), function (p) { var _a; return (_a = p.theme.sizes) === null || _a === void 0 ? void 0 : _a.medium; }, function (p) { return p.css; }, function (p) { var _a; return "margin: ".concat((_a = p.theme.sizes) === null || _a === void 0 ? void 0 : _a.normal, " 0;"); });
65
+ var templateObject_1, templateObject_2;
@@ -0,0 +1,42 @@
1
+ import { Category, Tag } from '@telia-ace/knowledge-widget-core';
2
+ import { Container } from '@webprovisions/platform';
3
+ export declare type SearchComponentProps = {
4
+ route?: string;
5
+ role?: string;
6
+ showSearchButton: boolean;
7
+ showClearButton: boolean;
8
+ showChildren: boolean;
9
+ searchButtonLabel: string;
10
+ clearButtonLabel: string;
11
+ ariaLabel?: string;
12
+ placeholder: string;
13
+ autoFocus: boolean;
14
+ incremental?: boolean | number;
15
+ filterBadges?: FilterConfig | boolean;
16
+ activeFilterBadges?: ActiveFilterBadges;
17
+ deleteFilterBadgeAriaLabel?: string;
18
+ quickFilters?: FilterConfig | boolean;
19
+ quickFilter?: Filter;
20
+ patchParams?: boolean;
21
+ };
22
+ export declare type Filter = {
23
+ items?: Category[] | Tag[];
24
+ type?: 'guideCategory' | 'tag';
25
+ symbol?: string;
26
+ loading: boolean;
27
+ open: boolean;
28
+ };
29
+ export declare type ActiveFilterBadges = {
30
+ guideCategory?: Category | null;
31
+ tag?: Tag | null;
32
+ tooltip?: string | null;
33
+ initial?: boolean;
34
+ };
35
+ export declare type FilterConfig = {
36
+ autoSelect?: boolean;
37
+ guideCategory?: boolean;
38
+ tag?: boolean;
39
+ position?: 'inside' | 'below';
40
+ };
41
+ declare const SearchComponent: (container: Container) => Promise<void>;
42
+ export default SearchComponent;