@reykjavik/hanna-react 0.10.114 → 0.10.115

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/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@
4
4
 
5
5
  - ... <!-- Add new lines here. -->
6
6
 
7
+ ## 0.10.115
8
+
9
+ _2024-01-09_
10
+
11
+ - feat: Add `getSearchContent` prop to `Multiselect`
12
+ - feat: Change icon on `MainMenu2`'s toggler button when menu is open
13
+
7
14
  ## 0.10.114
8
15
 
9
16
  _2023-12-13_
package/MainMenu2.js CHANGED
@@ -194,18 +194,20 @@ const MainMenu2 = (props) => {
194
194
  isMenuOpen && react_1.default.createElement(FocusTrap_js_1.FocusTrap, { atTop: true }),
195
195
  react_1.default.createElement("div", { className: "MainMenu2__content" },
196
196
  react_1.default.createElement("h2", { className: "MainMenu2__title" }, txt.title),
197
- isBrowser ? (react_1.default.createElement(ButtonPrimary_js_1.default, Object.assign({ className: "MainMenu2__toggler", size: "small", type: "button", "aria-pressed": isMenuOpen, "aria-controls": menuId, "data-icon": "text" }, (isMenuOpen
197
+ isBrowser ? (react_1.default.createElement(ButtonPrimary_js_1.default, Object.assign({ className: "MainMenu2__toggler", size: "small", type: "button", "aria-pressed": isMenuOpen, "aria-controls": menuId }, (isMenuOpen
198
198
  ? {
199
199
  onClick: closeMenu,
200
200
  'aria-label': txt.closeMenuLong,
201
201
  title: txt.closeMenuLong,
202
202
  children: txt.closeMenu,
203
+ 'data-icon': 'text',
203
204
  }
204
205
  : {
205
206
  onClick: openMenu,
206
207
  'aria-label': txt.openMenuLong,
207
208
  title: txt.openMenuLong,
208
209
  children: txt.openMenu,
210
+ 'data-icon': 'close',
209
211
  })))) : (react_1.default.createElement(ButtonPrimary_js_1.default, { className: "MainMenu2__toggler", size: "small", href: `#${menuId}`, onClick: a11yHelpers_js_1.handleAnchorLinkClick, "aria-hidden": "true", "data-icon": "text" }, txt.title)),
210
212
  mainItems && (react_1.default.createElement("div", { className: (0, classUtils_1.modifiedClass)('MainMenu2__main', activeSubmenu < 0 && 'noneActive') },
211
213
  renderItem('MainMenu2__main__', homeLinkItem, { Tag: 'div' }),
@@ -1,4 +1,4 @@
1
- import { TogglerGroupOptions } from '../_abstract/_TogglerGroup.js';
1
+ import { TogglerGroupOption, TogglerGroupOptions } from '../_abstract/_TogglerGroup.js';
2
2
  import { TogglerGroupFieldOption } from '../_abstract/_TogglerGroupField.js';
3
3
  export declare const _weights: {
4
4
  WHOLE_WORD: number;
@@ -13,7 +13,9 @@ item: TogglerGroupFieldOption<string>,
13
13
  /** Trimmed list of `toLowerCase`d query words */
14
14
  queryWords: Array<string>,
15
15
  /** The raw, untouched search query as typed by the user */
16
- rawQuery: string) => number;
16
+ rawQuery: string,
17
+ /** Function to extract the item's label */
18
+ itemContent: string | undefined) => number;
17
19
  export declare const defaultSearchScoring: SearchScoringfn;
18
20
  /** Returns a normalized, filtered list of options */
19
- export declare const filterItems: <Extras = Record<string, never>>(options: TogglerGroupOptions<string, Extras>, searchQuery: string, searchScoringFn?: SearchScoringfn) => TogglerGroupOptions<string, Extras>;
21
+ export declare const filterItems: <Extras = Record<string, never>>(options: TogglerGroupOptions<string, Extras>, searchQuery: string, searchScoringFn?: SearchScoringfn, getLabel?: (item: TogglerGroupOption<string, Extras>) => string | undefined) => TogglerGroupOptions<string, Extras>;
@@ -47,13 +47,12 @@ const calcScore = (itemString, queryWords) => {
47
47
  });
48
48
  return score;
49
49
  };
50
- const defaultSearchScoring = (item, queryWords) => {
51
- var _a;
50
+ const defaultSearchScoring = (item, queryWords, _, itemContent) => {
52
51
  if (!item.value) {
53
52
  return 0;
54
53
  }
55
54
  const value = item.value.toLowerCase().trim();
56
- const label = ((_a = item.label) === null || _a === void 0 ? void 0 : _a.toLowerCase().trim()) || value;
55
+ const label = (itemContent === null || itemContent === void 0 ? void 0 : itemContent.toLowerCase().trim()) || value;
57
56
  let score = calcScore(label, queryWords);
58
57
  if (!score) {
59
58
  score = VALUE_WEIGHT * calcScore(value, queryWords);
@@ -65,7 +64,7 @@ exports.defaultSearchScoring = defaultSearchScoring;
65
64
  // banana emoji
66
65
  const SEP = '🍌';
67
66
  /** Returns a normalized, filtered list of options */
68
- const filterItems = (options, searchQuery, searchScoringFn = exports.defaultSearchScoring) => {
67
+ const filterItems = (options, searchQuery, searchScoringFn = exports.defaultSearchScoring, getLabel = (item) => item.label) => {
69
68
  if (!searchQuery.trim()) {
70
69
  return options;
71
70
  }
@@ -74,7 +73,7 @@ const filterItems = (options, searchQuery, searchScoringFn = exports.defaultSear
74
73
  return (options
75
74
  .map((item) => ({
76
75
  item,
77
- score: searchScoringFn(item, queryWords, searchQuery),
76
+ score: searchScoringFn(item, queryWords, searchQuery, getLabel(item)),
78
77
  }))
79
78
  .filter(({ score }) => score > 0)
80
79
  .sort((a, b) => (a.score === b.score ? 0 : a.score < b.score ? 1 : -1))
package/Multiselect.d.ts CHANGED
@@ -29,6 +29,11 @@ export type MultiselectProps = TogglerGroupFieldProps<string, {
29
29
  * A score of zero (or less) means the item is not a valid match.
30
30
  */
31
31
  searchScoring?: SearchScoringfn;
32
+ /**
33
+ * Custom function to extract the searchable content from a given option item.
34
+ * By default, the `label` property is used.
35
+ */
36
+ getSearchContent?: (item: MultiselectOption) => string;
32
37
  /**
33
38
  * Force display the current values at the top of the dropdown,
34
39
  * even when the total options are fewer than
package/Multiselect.js CHANGED
@@ -97,7 +97,7 @@ const Multiselect = (props) => {
97
97
  */
98
98
  const showCurrentValues = values.length > 0 &&
99
99
  (props.forceSummary || !isOpen || options.length >= summaryLimit);
100
- const filteredOptions = (0, react_1.useMemo)(() => (0, _Multiselect_search_js_1.filterItems)(options, searchQuery, props.searchScoring), [searchQuery, options, props.searchScoring]);
100
+ const filteredOptions = (0, react_1.useMemo)(() => (0, _Multiselect_search_js_1.filterItems)(options, searchQuery, props.searchScoring, props.getSearchContent), [searchQuery, options, props.searchScoring, props.getSearchContent]);
101
101
  const isFiltered = options !== filteredOptions;
102
102
  const handleCheckboxSelection = (0, react_1.useCallback)((selectedItem) => {
103
103
  const selValue = selectedItem.value;
package/esm/MainMenu2.js CHANGED
@@ -190,18 +190,20 @@ export const MainMenu2 = (props) => {
190
190
  isMenuOpen && React.createElement(FocusTrap, { atTop: true }),
191
191
  React.createElement("div", { className: "MainMenu2__content" },
192
192
  React.createElement("h2", { className: "MainMenu2__title" }, txt.title),
193
- isBrowser ? (React.createElement(ButtonPrimary, Object.assign({ className: "MainMenu2__toggler", size: "small", type: "button", "aria-pressed": isMenuOpen, "aria-controls": menuId, "data-icon": "text" }, (isMenuOpen
193
+ isBrowser ? (React.createElement(ButtonPrimary, Object.assign({ className: "MainMenu2__toggler", size: "small", type: "button", "aria-pressed": isMenuOpen, "aria-controls": menuId }, (isMenuOpen
194
194
  ? {
195
195
  onClick: closeMenu,
196
196
  'aria-label': txt.closeMenuLong,
197
197
  title: txt.closeMenuLong,
198
198
  children: txt.closeMenu,
199
+ 'data-icon': 'text',
199
200
  }
200
201
  : {
201
202
  onClick: openMenu,
202
203
  'aria-label': txt.openMenuLong,
203
204
  title: txt.openMenuLong,
204
205
  children: txt.openMenu,
206
+ 'data-icon': 'close',
205
207
  })))) : (React.createElement(ButtonPrimary, { className: "MainMenu2__toggler", size: "small", href: `#${menuId}`, onClick: handleAnchorLinkClick, "aria-hidden": "true", "data-icon": "text" }, txt.title)),
206
208
  mainItems && (React.createElement("div", { className: modifiedClass('MainMenu2__main', activeSubmenu < 0 && 'noneActive') },
207
209
  renderItem('MainMenu2__main__', homeLinkItem, { Tag: 'div' }),
@@ -1,4 +1,4 @@
1
- import { TogglerGroupOptions } from '../_abstract/_TogglerGroup.js';
1
+ import { TogglerGroupOption, TogglerGroupOptions } from '../_abstract/_TogglerGroup.js';
2
2
  import { TogglerGroupFieldOption } from '../_abstract/_TogglerGroupField.js';
3
3
  export declare const _weights: {
4
4
  WHOLE_WORD: number;
@@ -13,7 +13,9 @@ item: TogglerGroupFieldOption<string>,
13
13
  /** Trimmed list of `toLowerCase`d query words */
14
14
  queryWords: Array<string>,
15
15
  /** The raw, untouched search query as typed by the user */
16
- rawQuery: string) => number;
16
+ rawQuery: string,
17
+ /** Function to extract the item's label */
18
+ itemContent: string | undefined) => number;
17
19
  export declare const defaultSearchScoring: SearchScoringfn;
18
20
  /** Returns a normalized, filtered list of options */
19
- export declare const filterItems: <Extras = Record<string, never>>(options: TogglerGroupOptions<string, Extras>, searchQuery: string, searchScoringFn?: SearchScoringfn) => TogglerGroupOptions<string, Extras>;
21
+ export declare const filterItems: <Extras = Record<string, never>>(options: TogglerGroupOptions<string, Extras>, searchQuery: string, searchScoringFn?: SearchScoringfn, getLabel?: (item: TogglerGroupOption<string, Extras>) => string | undefined) => TogglerGroupOptions<string, Extras>;
@@ -44,13 +44,12 @@ const calcScore = (itemString, queryWords) => {
44
44
  });
45
45
  return score;
46
46
  };
47
- export const defaultSearchScoring = (item, queryWords) => {
48
- var _a;
47
+ export const defaultSearchScoring = (item, queryWords, _, itemContent) => {
49
48
  if (!item.value) {
50
49
  return 0;
51
50
  }
52
51
  const value = item.value.toLowerCase().trim();
53
- const label = ((_a = item.label) === null || _a === void 0 ? void 0 : _a.toLowerCase().trim()) || value;
52
+ const label = (itemContent === null || itemContent === void 0 ? void 0 : itemContent.toLowerCase().trim()) || value;
54
53
  let score = calcScore(label, queryWords);
55
54
  if (!score) {
56
55
  score = VALUE_WEIGHT * calcScore(value, queryWords);
@@ -61,7 +60,7 @@ export const defaultSearchScoring = (item, queryWords) => {
61
60
  // banana emoji
62
61
  const SEP = '🍌';
63
62
  /** Returns a normalized, filtered list of options */
64
- export const filterItems = (options, searchQuery, searchScoringFn = defaultSearchScoring) => {
63
+ export const filterItems = (options, searchQuery, searchScoringFn = defaultSearchScoring, getLabel = (item) => item.label) => {
65
64
  if (!searchQuery.trim()) {
66
65
  return options;
67
66
  }
@@ -70,7 +69,7 @@ export const filterItems = (options, searchQuery, searchScoringFn = defaultSearc
70
69
  return (options
71
70
  .map((item) => ({
72
71
  item,
73
- score: searchScoringFn(item, queryWords, searchQuery),
72
+ score: searchScoringFn(item, queryWords, searchQuery, getLabel(item)),
74
73
  }))
75
74
  .filter(({ score }) => score > 0)
76
75
  .sort((a, b) => (a.score === b.score ? 0 : a.score < b.score ? 1 : -1))
@@ -29,6 +29,11 @@ export type MultiselectProps = TogglerGroupFieldProps<string, {
29
29
  * A score of zero (or less) means the item is not a valid match.
30
30
  */
31
31
  searchScoring?: SearchScoringfn;
32
+ /**
33
+ * Custom function to extract the searchable content from a given option item.
34
+ * By default, the `label` property is used.
35
+ */
36
+ getSearchContent?: (item: MultiselectOption) => string;
32
37
  /**
33
38
  * Force display the current values at the top of the dropdown,
34
39
  * even when the total options are fewer than
@@ -93,7 +93,7 @@ export const Multiselect = (props) => {
93
93
  */
94
94
  const showCurrentValues = values.length > 0 &&
95
95
  (props.forceSummary || !isOpen || options.length >= summaryLimit);
96
- const filteredOptions = useMemo(() => filterItems(options, searchQuery, props.searchScoring), [searchQuery, options, props.searchScoring]);
96
+ const filteredOptions = useMemo(() => filterItems(options, searchQuery, props.searchScoring, props.getSearchContent), [searchQuery, options, props.searchScoring, props.getSearchContent]);
97
97
  const isFiltered = options !== filteredOptions;
98
98
  const handleCheckboxSelection = useCallback((selectedItem) => {
99
99
  const selValue = selectedItem.value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reykjavik/hanna-react",
3
- "version": "0.10.114",
3
+ "version": "0.10.115",
4
4
  "author": "Reykjavík (http://www.reykjavik.is)",
5
5
  "contributors": [
6
6
  "Hugsmiðjan ehf (http://www.hugsmidjan.is)",