@geotab/zenith 3.13.0-beta.1 → 3.13.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +3 -1
  2. package/dist/commonHelpers/hooks/usePillSize.js +2 -2
  3. package/dist/controlledPopup/controlledPopup.d.ts +4 -1
  4. package/dist/controlledPopup/controlledPopup.js +2 -2
  5. package/dist/filters/components/filtersContainer.js +64 -7
  6. package/dist/filters/components/filtersSearch.d.ts +7 -2
  7. package/dist/filters/components/filtersSearch.js +36 -72
  8. package/dist/filters/components/filtersSearchList.js +18 -35
  9. package/dist/filters/filters.d.ts +2 -0
  10. package/dist/filters/filters.js +66 -180
  11. package/dist/filters/filtersHelper.js +1 -1
  12. package/dist/groupsFilterRaw/groupsFilterRaw.js +7 -1
  13. package/dist/index.css +158 -69
  14. package/dist/inputAdornments/inputAdornments.d.ts +2 -1
  15. package/dist/inputAdornments/inputAdornments.js +2 -2
  16. package/dist/searchInputRaw/searchInputRaw.js +6 -2
  17. package/dist/searchInputRaw/types.d.ts +4 -0
  18. package/dist/utils/localization/translations/en.json +1 -0
  19. package/dist/utils/positioningUtils/calculatePosition.js +3 -1
  20. package/dist/utils/positioningUtils/normalizeVertically.js +1 -1
  21. package/esm/commonHelpers/hooks/usePillSize.js +2 -2
  22. package/esm/controlledPopup/controlledPopup.d.ts +4 -1
  23. package/esm/controlledPopup/controlledPopup.js +2 -2
  24. package/esm/filters/components/filtersContainer.js +65 -8
  25. package/esm/filters/components/filtersSearch.d.ts +7 -2
  26. package/esm/filters/components/filtersSearch.js +36 -49
  27. package/esm/filters/components/filtersSearchList.js +18 -35
  28. package/esm/filters/filters.d.ts +2 -0
  29. package/esm/filters/filters.js +67 -181
  30. package/esm/filters/filtersHelper.js +1 -1
  31. package/esm/groupsFilterRaw/groupsFilterRaw.js +7 -1
  32. package/esm/inputAdornments/inputAdornments.d.ts +2 -1
  33. package/esm/inputAdornments/inputAdornments.js +2 -2
  34. package/esm/searchInputRaw/searchInputRaw.js +6 -2
  35. package/esm/searchInputRaw/types.d.ts +4 -0
  36. package/esm/utils/localization/translations/en.json +1 -0
  37. package/esm/utils/positioningUtils/calculatePosition.js +3 -1
  38. package/esm/utils/positioningUtils/normalizeVertically.js +1 -1
  39. package/package.json +1 -1
@@ -4,10 +4,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  import { useCallback, useEffect, useId, useMemo, useState } from "react";
5
5
  import { flushSync } from "react-dom";
6
6
  import React from "react";
7
- import { ALL_SELECT_OPTION_ID, FiltersSelect, getAllOption, getFiltersSearchTypeAllOption } from "./components/filtersSelect";
7
+ import { getFiltersSearchTypeAllOption } from "./components/filtersSelect";
8
8
  import { classNames } from "../commonHelpers/classNames/classNames";
9
- import { TextIconButton } from "../textIconButton/textIconButton";
10
- import { IconChevronDownSmall } from "../icons/iconChevronDownSmall";
11
9
  import { useLanguage } from "../utils/localization/useLanguage";
12
10
  import { ControlledPopup } from "../controlledPopup/controlledPopup";
13
11
  import { FiltersContainer } from "./components/filtersContainer";
@@ -26,12 +24,12 @@ import { IconFilter } from "../icons/iconFilter";
26
24
  import { FiltersSidePanel } from "./components/filtersSidePanel";
27
25
  import { FiltersDateInput } from "./components/filtersDateInput";
28
26
  import { useMobile } from "../commonHelpers/hooks/useMobile";
29
- import { IconChevronTopSmall } from "../icons/iconChevronTopSmall";
30
27
  import { FOCUSABLE_SELECTOR } from "../utils/focusableSelector";
31
- import { Button } from "../button/button";
32
28
  import { FiltersSelectCompact } from "./components/filtersSelectCompact";
33
29
  import { FiltersSidePanelProvider } from "./components/filtersSidePanelProvider";
34
30
  import { zen } from "../utils/zen";
31
+ import { alignments } from "../utils/positioningUtils/alignments";
32
+ /** Bottom clearance in px kept between the popup and the viewport bottom edge. */
35
33
  injectString("cs", "Open setting conditions popup", "Open setting conditions popup");
36
34
  injectString("da-DK", "Open setting conditions popup", "Open setting conditions popup");
37
35
  injectString("de", "Open setting conditions popup", "Open setting conditions popup");
@@ -59,87 +57,7 @@ injectString("zh-Hans", "Open setting conditions popup", "Open setting condition
59
57
  injectString("zh-TW", "Open setting conditions popup", "Open setting conditions popup");
60
58
  injectString("ro-RO", "Open setting conditions popup", "Deschide\u021Bi pop-up-ul cu condi\u021Bii de setare");
61
59
  injectString("ar", "Open setting conditions popup", "\u0641\u062A\u062D \u0646\u0627\u0641\u0630\u0629 \u0625\u0639\u062F\u0627\u062F \u0627\u0644\u0634\u0631\u0648\u0637");
62
- injectString("cs", "Search page", "Search page");
63
- injectString("da-DK", "Search page", "Search page");
64
- injectString("de", "Search page", "Search page");
65
- injectString("en", "Search page", "Search page");
66
- injectString("es", "Search page", "Search page");
67
- injectString("fi-FI", "Search page", "Search page");
68
- injectString("fr", "Search page", "Search page");
69
- injectString("fr-FR", "Search page", "Search page");
70
- injectString("hu-HU", "Search page", "Search page");
71
- injectString("id", "Search page", "Search page");
72
- injectString("it", "Search page", "Search page");
73
- injectString("ja", "Search page", "Search page");
74
- injectString("ko-KR", "Search page", "Search page");
75
- injectString("ms", "Search page", "Search page");
76
- injectString("nb-NO", "Search page", "Search page");
77
- injectString("nl", "Search page", "Search page");
78
- injectString("pl", "Search page", "Search page");
79
- injectString("pt-BR", "Search page", "Search page");
80
- injectString("pt-PT", "Search page", "Pesquisar p\xE1gina");
81
- injectString("sk-SK", "Search page", "Search page");
82
- injectString("sv", "Search page", "Search page");
83
- injectString("th", "Search page", "Search page");
84
- injectString("tr", "Search page", "Search page");
85
- injectString("zh-Hans", "Search page", "Search page");
86
- injectString("zh-TW", "Search page", "Search page");
87
- injectString("ro-RO", "Search page", "C\u0103uta\u021Bi pagina");
88
- injectString("ar", "Search page", "\u0635\u0641\u062D\u0629 \u0627\u0644\u0628\u062D\u062B");
89
- injectString("cs", "Close setting conditions popup", "Close setting conditions popup");
90
- injectString("da-DK", "Close setting conditions popup", "Close setting conditions popup");
91
- injectString("de", "Close setting conditions popup", "Close setting conditions popup");
92
- injectString("en", "Close setting conditions popup", "Close setting conditions popup");
93
- injectString("es", "Close setting conditions popup", "Close setting conditions popup");
94
- injectString("fi-FI", "Close setting conditions popup", "Close setting conditions popup");
95
- injectString("fr", "Close setting conditions popup", "Close setting conditions popup");
96
- injectString("fr-FR", "Close setting conditions popup", "Close setting conditions popup");
97
- injectString("hu-HU", "Close setting conditions popup", "Close setting conditions popup");
98
- injectString("id", "Close setting conditions popup", "Close setting conditions popup");
99
- injectString("it", "Close setting conditions popup", "Close setting conditions popup");
100
- injectString("ja", "Close setting conditions popup", "Close setting conditions popup");
101
- injectString("ko-KR", "Close setting conditions popup", "Close setting conditions popup");
102
- injectString("ms", "Close setting conditions popup", "Close setting conditions popup");
103
- injectString("nb-NO", "Close setting conditions popup", "Close setting conditions popup");
104
- injectString("nl", "Close setting conditions popup", "Close setting conditions popup");
105
- injectString("pl", "Close setting conditions popup", "Close setting conditions popup");
106
- injectString("pt-BR", "Close setting conditions popup", "Close setting conditions popup");
107
- injectString("pt-PT", "Close setting conditions popup", "Fechar o pop-up de condi\xE7\xF5es de configura\xE7\xE3o");
108
- injectString("sk-SK", "Close setting conditions popup", "Close setting conditions popup");
109
- injectString("sv", "Close setting conditions popup", "Close setting conditions popup");
110
- injectString("th", "Close setting conditions popup", "Close setting conditions popup");
111
- injectString("tr", "Close setting conditions popup", "Close setting conditions popup");
112
- injectString("zh-Hans", "Close setting conditions popup", "Close setting conditions popup");
113
- injectString("zh-TW", "Close setting conditions popup", "Close setting conditions popup");
114
- injectString("ro-RO", "Close setting conditions popup", "\xCEnchide\u021Bi pop-up-ul cu condi\u021Bii de setare");
115
- injectString("ar", "Close setting conditions popup", "\u0625\u063A\u0644\u0627\u0642 \u0646\u0627\u0641\u0630\u0629 \u0625\u0639\u062F\u0627\u062F \u0627\u0644\u0634\u0631\u0648\u0637");
116
- injectString("cs", "Search by", "Search by");
117
- injectString("da-DK", "Search by", "Search by");
118
- injectString("de", "Search by", "Search by");
119
- injectString("en", "Search by", "Search by");
120
- injectString("es", "Search by", "Search by");
121
- injectString("fi-FI", "Search by", "Search by");
122
- injectString("fr", "Search by", "Search by");
123
- injectString("fr-FR", "Search by", "Search by");
124
- injectString("hu-HU", "Search by", "Search by");
125
- injectString("id", "Search by", "Search by");
126
- injectString("it", "Search by", "Search by");
127
- injectString("ja", "Search by", "Search by");
128
- injectString("ko-KR", "Search by", "Search by");
129
- injectString("ms", "Search by", "Search by");
130
- injectString("nb-NO", "Search by", "Search by");
131
- injectString("nl", "Search by", "Search by");
132
- injectString("pl", "Search by", "Search by");
133
- injectString("pt-BR", "Search by", "Search by");
134
- injectString("pt-PT", "Search by", "Pesquisar por");
135
- injectString("sk-SK", "Search by", "Search by");
136
- injectString("sv", "Search by", "Search by");
137
- injectString("th", "Search by", "Search by");
138
- injectString("tr", "Search by", "Search by");
139
- injectString("zh-Hans", "Search by", "Search by");
140
- injectString("zh-TW", "Search by", "Search by");
141
- injectString("ro-RO", "Search by", "C\u0103uta\u021Bi dup\u0103");
142
- injectString("ar", "Search by", "\u0627\u0644\u0628\u062D\u062B \u062D\u0633\u0628");
60
+ injectString("en", "Find in page", "Find in page");
143
61
  injectString("cs", "Setting conditions", "Setting conditions");
144
62
  injectString("da-DK", "Setting conditions", "Setting conditions");
145
63
  injectString("de", "Setting conditions", "Setting conditions");
@@ -167,33 +85,6 @@ injectString("zh-Hans", "Setting conditions", "Setting conditions");
167
85
  injectString("zh-TW", "Setting conditions", "Setting conditions");
168
86
  injectString("ro-RO", "Setting conditions", "Condi\u021Bii de setare");
169
87
  injectString("ar", "Setting conditions", "\u0625\u0639\u062F\u0627\u062F \u0627\u0644\u0634\u0631\u0648\u0637");
170
- injectString("cs", "Cancel", "Zru\u0161it");
171
- injectString("da-DK", "Cancel", "Annuller");
172
- injectString("de", "Cancel", "Abbrechen");
173
- injectString("en", "Cancel", "Cancel");
174
- injectString("es", "Cancel", "Cancelar");
175
- injectString("fi-FI", "Cancel", "Peruuta");
176
- injectString("fr", "Cancel", "Annuler");
177
- injectString("fr-FR", "Cancel", "Annuler");
178
- injectString("hu-HU", "Cancel", "M\xE9gse");
179
- injectString("id", "Cancel", "Batalkan");
180
- injectString("it", "Cancel", "Annullare");
181
- injectString("ja", "Cancel", "\u30AD\u30E3\u30F3\u30BB\u30EB");
182
- injectString("ko-KR", "Cancel", "\uCDE8\uC18C");
183
- injectString("ms", "Cancel", "Batal");
184
- injectString("nb-NO", "Cancel", "Avbryt");
185
- injectString("nl", "Cancel", "Annuleren");
186
- injectString("pl", "Cancel", "Anuluj");
187
- injectString("pt-BR", "Cancel", "Cancelar");
188
- injectString("pt-PT", "Cancel", "Cancelar");
189
- injectString("sk-SK", "Cancel", "Zru\u0161.");
190
- injectString("sv", "Cancel", "Avbryt");
191
- injectString("th", "Cancel", "\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01");
192
- injectString("tr", "Cancel", "\u0130ptal");
193
- injectString("zh-Hans", "Cancel", "\u53D6\u6D88");
194
- injectString("zh-TW", "Cancel", "\u53D6\u6D88");
195
- injectString("ro-RO", "Cancel", "Anula\u021Bi");
196
- injectString("ar", "Cancel", "\u0625\u0644\u063A\u0627\u0621");
197
88
  injectString("cs", "Filters and search", "Filters and search");
198
89
  injectString("da-DK", "Filters and search", "Filters and search");
199
90
  injectString("de", "Filters and search", "Filters and search");
@@ -221,6 +112,42 @@ injectString("zh-Hans", "Filters and search", "Filters and search");
221
112
  injectString("zh-TW", "Filters and search", "Filters and search");
222
113
  injectString("ro-RO", "Filters and search", "Filters and search");
223
114
  injectString("ar", "Filters and search", "\u0627\u0644\u062A\u0635\u0641\u064A\u0627\u062A \u0648\u0627\u0644\u0628\u062D\u062B");
115
+ const POPUP_BOTTOM_MARGIN = 36;
116
+ /**
117
+ * Custom alignment for the filters search popup.
118
+ * Returns a `height` constraint so calculatePosition sets maxHeight before the
119
+ * overflow check, anchoring the popup at the trigger top without repositioning.
120
+ */
121
+ const filtersPopupAlignment = Object.assign(Object.assign({}, alignments), {
122
+ "bottom-left": (triggerRect, _1, parentRect, _2, paddingY) => ({
123
+ top: triggerRect.top - parentRect.top + triggerRect.height + paddingY,
124
+ left: triggerRect.left - parentRect.left,
125
+ height: (zen.innerHeight || 0) - triggerRect.top - POPUP_BOTTOM_MARGIN
126
+ }),
127
+ "bottom-right": (triggerRect, _1, parentRect, _2, paddingY) => ({
128
+ top: triggerRect.top - parentRect.top + triggerRect.height + paddingY,
129
+ right: parentRect.right - triggerRect.right,
130
+ height: (zen.innerHeight || 0) - triggerRect.top - POPUP_BOTTOM_MARGIN
131
+ })
132
+ });
133
+ /**
134
+ * Mobile variant: popup starts at left:0 and spans the full parent width.
135
+ * top:0 aligns the popup with the top of the trigger row.
136
+ */
137
+ const filtersPopupAlignmentMobile = Object.assign(Object.assign({}, alignments), {
138
+ "bottom-left": (triggerRect, _1, parentRect) => ({
139
+ top: 0,
140
+ left: 0,
141
+ width: parentRect.right - parentRect.left,
142
+ height: (zen.innerHeight || 0) - triggerRect.top - POPUP_BOTTOM_MARGIN
143
+ }),
144
+ "bottom-right": (triggerRect, _1, parentRect) => ({
145
+ top: 0,
146
+ right: 0,
147
+ width: parentRect.right - parentRect.left,
148
+ height: (zen.innerHeight || 0) - triggerRect.top - POPUP_BOTTOM_MARGIN
149
+ })
150
+ });
224
151
  export const FiltersDisplayName = "Filters";
225
152
  /**
226
153
  * @beta This component is currently in beta.
@@ -245,7 +172,8 @@ export const Filters = ({
245
172
  onSaveRecentSearch,
246
173
  savedFilters,
247
174
  onRemoveSavedFilter,
248
- onSaveFilter
175
+ onSaveFilter,
176
+ searchPlaceholder
249
177
  }) => {
250
178
  const [isOpen, setIsOpen] = useState(false);
251
179
  const isSavedFiltersMode = Boolean(savedFilters && onRemoveSavedFilter && onSaveFilter);
@@ -481,12 +409,6 @@ export const Filters = ({
481
409
  return foundType && foundType.icon ? foundType.icon : IconFilter;
482
410
  }, [searchTypesArray]);
483
411
  const combinedData = useCombineData(searchTypesArray);
484
- const memoizedSelect = useMemo(() => _jsx(FiltersSelect, {
485
- value: searchType || getFiltersSearchTypeAllOption(),
486
- selectListRef: selectListRef,
487
- onChange: setSearchType,
488
- items: searchTypesToSelect
489
- }), [searchType, searchTypesToSelect, setSearchType]);
490
412
  const memoizedSelectCompact = useMemo(() => _jsx(FiltersSelectCompact, {
491
413
  value: searchType || getFiltersSearchTypeAllOption(),
492
414
  selectListRef: selectListCompactRef,
@@ -513,27 +435,28 @@ export const Filters = ({
513
435
  return _jsx(FiltersSearch, Object.assign({
514
436
  id: `filtersSearch_${uniqueKey}`,
515
437
  ref: searchTriggerRef,
516
- name: translate("Search page"),
438
+ containerRef: triggerRef,
439
+ name: searchPlaceholder || translate("Find in page"),
517
440
  value: keyword,
518
441
  onSearchKeyDown: handleSearchKeyDown,
519
442
  onOpenPopup: isOpen ? undefined : handleOpenChange.bind(null, true),
520
443
  onChange: handleSearchKeywordChange,
521
- handleRemove: onSearchItemClick,
522
444
  searchSelection: searchSelection,
523
- className: "zen-filters__search-with-pills"
445
+ className: "zen-filters__search-with-pills",
446
+ isMobile: isMobile
524
447
  }, popupAttributes));
525
- }, [isEmptySearchBar, uniqueKey, translate, keyword, handleSearchKeyDown, isOpen, handleOpenChange, handleSearchKeywordChange, onSearchItemClick, searchSelection, popupId, redundantPopup]);
448
+ }, [isEmptySearchBar, uniqueKey, translate, keyword, handleSearchKeyDown, isOpen, handleOpenChange, handleSearchKeywordChange, searchSelection, popupId, redundantPopup, isMobile, searchPlaceholder]);
526
449
  const memoizedSearchPopup = useMemo(() => isEmptySearchBar ? null : _jsx(FiltersSearch, {
527
450
  id: `filtersSearchPopup_${uniqueKey}`,
528
451
  ref: searchPopupTriggerRef,
529
- name: translate("Search page"),
452
+ name: searchPlaceholder || translate("Find in page"),
530
453
  value: keyword,
531
454
  onChange: setKeyword,
455
+ onClear: handleCancelSearchSelection,
532
456
  onSearchKeyDown: handleSearchKeyDown,
533
- handleRemove: onSearchItemClick,
534
457
  searchSelection: isMobile ? internalSearchSelection : searchSelection,
535
- className: "zen-filters-popup__search-with-pills"
536
- }), [isEmptySearchBar, uniqueKey, translate, keyword, setKeyword, handleSearchKeyDown, onSearchItemClick, isMobile, internalSearchSelection, searchSelection]);
458
+ className: classNames(["zen-filters-popup__search-with-pills", isMobile ? "zen-filters-search--mobile" : ""])
459
+ }), [isEmptySearchBar, uniqueKey, translate, keyword, setKeyword, handleCancelSearchSelection, handleSearchKeyDown, isMobile, internalSearchSelection, searchSelection, searchPlaceholder]);
537
460
  const memoizedSearchList = useMemo(() => !isOpen || isEmptySearchBar ? null : _jsx(FiltersSearchList, {
538
461
  searchValue: keyword,
539
462
  searchListRef: searchListRef,
@@ -549,74 +472,37 @@ export const Filters = ({
549
472
  applyButtonHandler: isMobile ? handleApplySearchSelection : undefined,
550
473
  isInitialSearchSelectionState: isMobile ? memoizedIsInitialSearchSelectionState : undefined
551
474
  }), [isOpen, keyword, combinedData, isMobile, internalSearchSelection, searchSelection, searchOnlyOneType, getIconByType, onInternalSearchItemClick, onSearchItemClick, onClearInternalSearchSelection, onClearSearchSelection, isRecentSearchesMode, recentSearches, onRemoveRecentSearchItem, handleRecentSearchItemClick, handleApplySearchSelection, memoizedIsInitialSearchSelectionState, isEmptySearchBar]);
552
- const allOption = useMemo(() => getAllOption(translate), [translate]);
553
- const selectTriggerPopup = useMemo(() => _jsx(TextIconButton, {
554
- className: "zen-filters__select-trigger",
555
- iconClasses: "zen-filters__select-trigger-icon",
556
- contentClasses: "zen-filters__select-trigger-content",
557
- title: translate("Close setting conditions popup"),
558
- onClick: handleOpenChange.bind(null, false),
559
- icon: IconChevronTopSmall,
560
- iconPosition: "end",
561
- children: translate("Search by")
562
- }), [handleOpenChange, translate]);
563
- // added onMouseDown to prevent focus
564
- const selectTrigger = useMemo(() => {
565
- var _a;
566
- if (isMobile || redundantPopup) {
567
- return null;
568
- }
569
- const currentSelectedType = selectState[0] === ALL_SELECT_OPTION_ID ? allOption.name : (_a = searchTypesArray.find(item => item.id === selectState[0])) === null || _a === void 0 ? void 0 : _a.name;
570
- return _jsx(TextIconButton, {
571
- tabIndex: -1,
572
- onMouseDown: e => e.preventDefault(),
573
- className: "zen-filters__select-trigger",
574
- iconClasses: "zen-filters__select-trigger-icon",
575
- contentClasses: "zen-filters__select-trigger-content",
576
- title: translate("Open setting conditions popup"),
577
- onClick: handleOpenChange.bind(null, true),
578
- icon: IconChevronDownSmall,
579
- iconPosition: "end",
580
- children: currentSelectedType
581
- });
582
- }, [isMobile, redundantPopup, translate, handleOpenChange, selectState, allOption.name, searchTypesArray]);
583
475
  const popupChangeHandler = useCallback(val => {
584
476
  (isMobile ? handleCancelSearchSelection : handleOpenChange)(val);
585
477
  }, [isMobile, handleCancelSearchSelection, handleOpenChange]);
586
478
  const memoizedPopup = useMemo(() => isEmptySearchBar || redundantPopup ? null : _jsx(ControlledPopup, {
587
- paddingY: -34,
479
+ paddingY: isMobile ? 0 : -34,
588
480
  isOpen: isOpen,
589
- className: classNames(["zen-filters-popup", isMobile ? "zen-filters-popup--mobile" : ""]),
481
+ className: classNames(["zen-filters-popup", "zen-filters-popup--mobile"]),
590
482
  onOpenChange: popupChangeHandler,
591
483
  useTrapFocusWithTrigger: "none",
592
- alignment: "bottom",
484
+ alignment: "bottom-start",
593
485
  shouldHoldScroll: true,
594
486
  preventAttributesAutoSet: true,
595
487
  triggerRef: triggerRef,
596
488
  ariaLabel: translate("Setting conditions"),
597
489
  recalculateOnScroll: true,
598
490
  id: popupId,
599
- children: _jsxs("div", {
491
+ alignmentsFn: isMobile ? filtersPopupAlignmentMobile : filtersPopupAlignment,
492
+ children: _jsx("div", {
600
493
  className: "zen-filters-popup__content",
601
- children: [isMobile ? null : _jsxs("div", {
602
- className: "zen-filters-popup__left-panel",
603
- children: [selectTriggerPopup, memoizedSelect]
604
- }), _jsxs("div", {
494
+ children: _jsxs("div", {
605
495
  className: "zen-filters-popup__right-panel",
606
- children: [_jsxs("div", {
607
- className: classNames(["zen-filters-popup__first-row", isMobile ? "zen-filters-popup__first-row--mobile" : ""]),
608
- children: [memoizedSearchPopup, isMobile ? _jsx(Button, {
609
- type: "tertiary",
610
- onClick: handleCancelSearchSelection,
611
- children: translate("Cancel")
612
- }) : null]
496
+ children: [_jsx("div", {
497
+ className: classNames(["zen-filters-popup__first-row", "zen-filters-popup__first-row--mobile"]),
498
+ children: memoizedSearchPopup
613
499
  }), _jsxs("div", {
614
- className: classNames(["zen-filters-popup__second-row", isMobile ? "zen-filters-popup__second-row--mobile" : ""]),
615
- children: [isMobile ? memoizedSelectCompact : null, memoizedSearchList]
500
+ className: classNames(["zen-filters-popup__second-row", "zen-filters-popup__second-row--mobile"]),
501
+ children: [memoizedSelectCompact, memoizedSearchList]
616
502
  })]
617
- })]
503
+ })
618
504
  })
619
- }), [isEmptySearchBar, redundantPopup, isOpen, isMobile, popupChangeHandler, handleCancelSearchSelection, translate, selectTriggerPopup, memoizedSelect, memoizedSearchPopup, memoizedSelectCompact, memoizedSearchList, popupId]);
505
+ }), [isEmptySearchBar, redundantPopup, isOpen, isMobile, popupChangeHandler, translate, memoizedSearchPopup, memoizedSelectCompact, memoizedSearchList, popupId]);
620
506
  const filtersForRender = useMemo(() => filters.filter(el => {
621
507
  const elProps = el.props;
622
508
  return typeof elProps.visible === "boolean" ? elProps.visible : elProps.visible === undefined ? false : elProps.visible(Array.from(selectState), undefined);
@@ -699,11 +585,11 @@ export const Filters = ({
699
585
  return _jsxs("section", {
700
586
  role: "search",
701
587
  "aria-label": translate("Filters and search"),
702
- className: classNames(["zen-filters", className || ""]),
703
- children: [isEmptySearchBar ? null : _jsxs("div", {
588
+ className: classNames(["zen-filters", isMobile ? "zen-filters--mobile" : "", className || ""]),
589
+ children: [isEmptySearchBar ? null : _jsx("div", {
704
590
  className: classNames(["zen-filters__main-row", isOpen ? "" : "zen-filters__main-row--initial", isMobile ? "zen-filters__main-row--mobile" : ""]),
705
591
  ref: triggerRef,
706
- children: [selectTrigger, memoizedSearch]
592
+ children: memoizedSearch
707
593
  }), _jsx(FiltersSavedItemsProvider, {
708
594
  items: memoizedSavedFiltersItems,
709
595
  active: memoizedSavedFiltersActive,
@@ -298,7 +298,7 @@ export const processChildrenWithMetaData = (children) => {
298
298
  // Component props provide: state, onChange, and other props
299
299
  const childProps = child.props;
300
300
  const { state, onChange } = childProps, otherProps = __rest(childProps, ["state", "onChange"]);
301
- const mergedProps = Object.assign(Object.assign({}, otherProps), { id: metaData.id, defaultState: createDefaultStateMetaData(metaData.defaultState || childProps.defaultState, metaData.childType, state), visible: metaData.visible, state,
301
+ const mergedProps = Object.assign(Object.assign({}, otherProps), { id: metaData.id, defaultState: createDefaultStateMetaData(metaData.defaultState || childProps.defaultState, metaData.childType, state), visible: childProps.visible !== undefined ? childProps.visible : metaData.visible, state,
302
302
  onChange, childType: metaData.childType });
303
303
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
304
304
  return React.cloneElement(child, mergedProps);
@@ -304,6 +304,7 @@ export const GroupsFilterRaw = props => {
304
304
  const menuRef = useRef(null);
305
305
  const prevInitialState = useRef(initialFilterStateInner);
306
306
  const prevSearchField = useRef("");
307
+ const attemptedFetchOnOpenRef = useRef(false);
307
308
  const groupsFilterId = useId();
308
309
  const popupId = useId();
309
310
  const blocksMap = useMemo(() => [["builtInGroups", "userGroups"], ["advancedGroups", "builtInGroups", "userGroups"], ["builtInGroups", "userGroups"]], []);
@@ -867,7 +868,12 @@ export const GroupsFilterRaw = props => {
867
868
  }), [handleApply, handleCancel, handleReset, isApplyDisabled, translate]);
868
869
  const isEmptyMap = dataItems.length === 0;
869
870
  useEffect(() => {
870
- if (isEmptyMap && uiState.isOpen && !uiState.isLoading && !uiState.hasError) {
871
+ if (!uiState.isOpen) {
872
+ attemptedFetchOnOpenRef.current = false;
873
+ return;
874
+ }
875
+ if (isEmptyMap && !attemptedFetchOnOpenRef.current && !uiState.isLoading && !uiState.hasError) {
876
+ attemptedFetchOnOpenRef.current = true;
871
877
  dispatchUiState({
872
878
  type: UiStateActionType.SetLoadWithError,
873
879
  payload: {
@@ -26,8 +26,9 @@ export interface IInputAdornments {
26
26
  ariaControls?: string;
27
27
  ariaHaspopup?: boolean | "dialog" | "menu" | "grid" | "true" | "false" | "listbox" | "tree";
28
28
  ariaExpanded?: boolean | "true" | "false";
29
+ autocomplete?: string;
29
30
  }
30
31
  export declare const InputAdornments: {
31
- ({ id, value, className, disabled, isError, maxLength, onChange, onKeyDown, onFocus, startAdornment, endAdornment, placeholder, inputType, autoFocus, name, onBlur, ref, ariaLabel, ariaDescribedby, role, ariaAutocomplete, ariaControls, ariaHaspopup, ariaExpanded }: IInputAdornments): import("react/jsx-runtime").JSX.Element;
32
+ ({ id, value, className, disabled, isError, maxLength, onChange, onKeyDown, onFocus, startAdornment, endAdornment, placeholder, inputType, autoFocus, name, onBlur, ref, ariaLabel, ariaDescribedby, role, ariaAutocomplete, ariaControls, ariaHaspopup, ariaExpanded, autocomplete }: IInputAdornments): import("react/jsx-runtime").JSX.Element;
32
33
  displayName: string;
33
34
  };
@@ -4,7 +4,7 @@ import { classNames } from "../commonHelpers/classNames/classNames";
4
4
  import { TextInputRaw } from "../textInputRaw/textInputRaw";
5
5
  import { useDriveClassName } from "../utils/theme/useDriveClassName";
6
6
  import { useMobileClassName } from "../utils/theme/useMobileClassName";
7
- export const InputAdornments = ({ id, value, className = "", disabled, isError, maxLength, onChange, onKeyDown, onFocus, startAdornment, endAdornment, placeholder, inputType = "text", autoFocus, name, onBlur, ref, ariaLabel, ariaDescribedby, role, ariaAutocomplete, ariaControls, ariaHaspopup, ariaExpanded }) => {
7
+ export const InputAdornments = ({ id, value, className = "", disabled, isError, maxLength, onChange, onKeyDown, onFocus, startAdornment, endAdornment, placeholder, inputType = "text", autoFocus, name, onBlur, ref, ariaLabel, ariaDescribedby, role, ariaAutocomplete, ariaControls, ariaHaspopup, ariaExpanded, autocomplete }) => {
8
8
  const disabledClassName = disabled ? "zen-input-adornments--disabled" : "";
9
9
  const driveComponentClass = useDriveClassName("zen-input-adornments");
10
10
  const mobileComponentClass = useMobileClassName("zen-input-adornments");
@@ -22,6 +22,6 @@ export const InputAdornments = ({ id, value, className = "", disabled, isError,
22
22
  !value ? "zen-input-adornments__wrapper--empty" : "",
23
23
  className
24
24
  ]), [className, endAdornment, value]);
25
- return (_jsxs("div", { className: classes, children: [!!startAdornment && _jsx("div", { className: "zen-input-adornments__adornment zen-input-adornments__adornment--start", children: startAdornment }), _jsx("div", { className: wrapperClasses, children: _jsx(TextInputRaw, { name: name, onBlur: onBlur, ref: ref, id: id, value: value, maxLength: maxLength, isError: isError, placeholder: placeholder, onChange: onChange, onKeyDown: onKeyDown, onFocus: onFocus, disabled: disabled, type: inputType, autoFocus: autoFocus, ariaLabel: ariaLabel, ariaDescribedby: ariaDescribedby, role: role, ariaAutocomplete: ariaAutocomplete, ariaControls: ariaControls, ariaHaspopup: ariaHaspopup, ariaExpanded: ariaExpanded === undefined ? undefined : ariaExpanded === "true" || ariaExpanded === true, className: "zen-input-adornments__input zen-input-adornments__input--border-none" }) }), !!endAdornment && _jsx("div", { className: "zen-input-adornments__adornment zen-input-adornments__adornment--end", children: endAdornment })] }));
25
+ return (_jsxs("div", { className: classes, children: [!!startAdornment && _jsx("div", { className: "zen-input-adornments__adornment zen-input-adornments__adornment--start", children: startAdornment }), _jsx("div", { className: wrapperClasses, children: _jsx(TextInputRaw, { name: name, onBlur: onBlur, ref: ref, id: id, value: value, maxLength: maxLength, isError: isError, placeholder: placeholder, onChange: onChange, onKeyDown: onKeyDown, onFocus: onFocus, disabled: disabled, type: inputType, autoFocus: autoFocus, ariaLabel: ariaLabel, ariaDescribedby: ariaDescribedby, role: role, ariaAutocomplete: ariaAutocomplete, ariaControls: ariaControls, ariaHaspopup: ariaHaspopup, ariaExpanded: ariaExpanded === undefined ? undefined : ariaExpanded === "true" || ariaExpanded === true, autocomplete: autocomplete, className: "zen-input-adornments__input zen-input-adornments__input--border-none" }) }), !!endAdornment && _jsx("div", { className: "zen-input-adornments__adornment zen-input-adornments__adornment--end", children: endAdornment })] }));
26
26
  };
27
27
  InputAdornments.displayName = "InputAdornments";
@@ -81,12 +81,14 @@ export const SearchInputRaw = props => {
81
81
  autoFocus,
82
82
  id,
83
83
  onFocus,
84
+ onClear,
84
85
  ref,
85
86
  role,
86
87
  ariaAutocomplete,
87
88
  ariaControls,
88
89
  ariaHaspopup,
89
- ariaExpanded
90
+ ariaExpanded,
91
+ autocomplete = "off"
90
92
  } = props;
91
93
  const {
92
94
  name,
@@ -120,6 +122,7 @@ export const SearchInputRaw = props => {
120
122
  const onClick = () => {
121
123
  var _a;
122
124
  onChange === null || onChange === void 0 ? void 0 : onChange("");
125
+ onClear === null || onClear === void 0 ? void 0 : onClear();
123
126
  // Return focus to the input after clearing so keyboard users don't lose their place (WCAG 2.1 SC 2.1.1)
124
127
  (_a = ref ? ref.current : innerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
125
128
  };
@@ -178,7 +181,8 @@ export const SearchInputRaw = props => {
178
181
  ariaAutocomplete: ariaAutocomplete,
179
182
  ariaControls: ariaControls,
180
183
  ariaHaspopup: ariaHaspopup,
181
- ariaExpanded: ariaExpanded === undefined ? undefined : ariaExpanded === "true" || ariaExpanded === true
184
+ ariaExpanded: ariaExpanded === undefined ? undefined : ariaExpanded === "true" || ariaExpanded === true,
185
+ autocomplete: autocomplete
182
186
  })
183
187
  }));
184
188
  };
@@ -8,6 +8,8 @@ export interface ISearchInputRawBase {
8
8
  placeholder?: string;
9
9
  ariaLabel?: string;
10
10
  closeButtonTitle?: string;
11
+ /** Called when the clear (X) button is clicked, in addition to clearing the value via onChange */
12
+ onClear?: () => void;
11
13
  isError?: boolean;
12
14
  isReadOnly?: boolean;
13
15
  maxLength?: number;
@@ -26,6 +28,8 @@ export interface ISearchInputRawBase {
26
28
  ariaControls?: string;
27
29
  ariaHaspopup?: boolean | "dialog" | "menu" | "grid" | "true" | "false" | "listbox" | "tree";
28
30
  ariaExpanded?: boolean | "true" | "false";
31
+ /** HTML autocomplete attribute for the underlying input. Defaults to "off" to suppress browser autofill. */
32
+ autocomplete?: string;
29
33
  }
30
34
  export interface ISearchInputRawDefault extends ISearchInputRawBase {
31
35
  value: string;
@@ -252,6 +252,7 @@
252
252
  "value changes in the range from {MIN} to {MAX}.": "value changes in the range from {MIN} to {MAX}.",
253
253
  "Error generating chart narrative for dataset": "Error generating chart narrative for dataset",
254
254
  "Chart data table and visualization": "Chart data table and visualization",
255
+ "Find in page": "Find in page",
255
256
  "Search page": "Search page",
256
257
  "Search by": "Search by",
257
258
  "Save": "Save",
@@ -90,7 +90,9 @@ export const calculatePosition = (triggerRef, popupRef, paddingX, paddingY, inli
90
90
  }
91
91
  }
92
92
  }
93
- else if (!isTopsideAlignment && triggerRect.y + triggerRect.height + popupRect.height > (zen.innerHeight || 0)) {
93
+ else if (!isTopsideAlignment &&
94
+ triggerRect.y + triggerRect.height + popupRect.height > (zen.innerHeight || 0) &&
95
+ position.height === undefined) {
94
96
  const newTopPosition = (zen.innerHeight || 0) + scrollTop - popupRect.height;
95
97
  position.top = newTopPosition < 0 ? 0 : newTopPosition;
96
98
  }
@@ -4,7 +4,7 @@ export const normalizeVertically = (position, popupRect, parentHeight) => {
4
4
  position.bottom = 0;
5
5
  return;
6
6
  }
7
- if (position.top) {
7
+ if (position.top !== undefined) {
8
8
  if (position.top < 0) {
9
9
  position.top = 0;
10
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geotab/zenith",
3
- "version": "3.13.0-beta.1",
3
+ "version": "3.13.1-beta.0",
4
4
  "description": "Zenith components library on React",
5
5
  "main": "dist/index.js",
6
6
  "types": "esm/index.d.ts",