@geotab/zenith 3.6.0-beta.6 → 3.6.0-beta.7

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/README.md CHANGED
@@ -59,7 +59,6 @@ Change log:
59
59
  - Update `Layout` component background
60
60
  - Improve y-axis positioning for `Charts`
61
61
  - Center content alignment in `TextIconButton` component
62
- - Enhanced `Nav` component: optional drag-and-drop, mobile menu state handling, action support
63
62
  - Add divider support for groupsFilter and pillExpandable
64
63
  - Add link support for mobile primary actions
65
64
  - Fix `Alert` component issues
@@ -68,6 +67,10 @@ Change log:
68
67
  - Accessibility improvements: table actions, aria-sort, checkbox focus and general accessibility fixes across components
69
68
  - Documentation updates: enhanced component examples and usage guidelines for `Dropdown`, `Chart`, `Select`
70
69
 
70
+ ### 3.5.1
71
+
72
+ Edit mode in the `Nav` component has been added.
73
+
71
74
  ### 3.5.0
72
75
 
73
76
  Accessibility improvements, new DateInput control in FiltersBar, custom chart legend formatting, and new languages support. Plus several performance and stability fixes.
@@ -303,8 +303,13 @@ const GroupsFilterRaw = props => {
303
303
  const prevSearchField = (0, react_1.useRef)("");
304
304
  const groupsFilterId = (0, react_1.useId)();
305
305
  const popupId = (0, react_1.useId)();
306
- const isDataLoadedRef = (0, react_1.useRef)(false);
307
306
  const blocksMap = (0, react_1.useMemo)(() => [["builtInGroups", "userGroups"], ["advancedGroups", "builtInGroups", "userGroups"], ["builtInGroups", "userGroups"]], []);
307
+ const onOptionsToggle = (0, react_1.useCallback)(() => {
308
+ dispatchUiState({
309
+ type: uiStateActionType_1.UiStateActionType.ToggleOpen,
310
+ payload: undefined
311
+ });
312
+ }, []);
308
313
  const handleSetStep = (0, react_1.useCallback)(newStep => {
309
314
  var _a;
310
315
  uiState.step !== groupsFilterInterfaces_1.FilterMenuStep.CurrentlySelected && dispatchUiState({
@@ -553,8 +558,7 @@ const GroupsFilterRaw = props => {
553
558
  errorHandler(e);
554
559
  return [];
555
560
  }), [dataLoader, errorHandler]);
556
- const loadData = (0, react_1.useCallback)(() => {
557
- isDataLoadedRef.current = true;
561
+ (0, react_1.useEffect)(() => {
558
562
  dispatchUiState({
559
563
  type: uiStateActionType_1.UiStateActionType.SetLoadWithError,
560
564
  payload: {
@@ -583,32 +587,9 @@ const GroupsFilterRaw = props => {
583
587
  isLoading: false
584
588
  }
585
589
  });
586
- isDataLoadedRef.current = false;
587
590
  errorHandler(e);
588
591
  });
589
592
  }, [dataLoader, errorHandler]);
590
- (0, react_1.useEffect)(() => {
591
- if (isDataLoadedRef.current) {
592
- return;
593
- }
594
- loadData();
595
- }, [loadData]);
596
- const onOptionsToggle = (0, react_1.useCallback)(() => {
597
- const willBeOpen = !uiState.isOpen;
598
- dispatchUiState({
599
- type: uiStateActionType_1.UiStateActionType.ToggleOpen,
600
- payload: undefined
601
- });
602
- if (willBeOpen && !isDataLoadedRef.current && !uiState.isLoading) {
603
- loadData();
604
- }
605
- }, [uiState.isOpen, uiState.isLoading, loadData]);
606
- const isEmptyMap = dataItems.length === 0;
607
- (0, react_1.useEffect)(() => {
608
- if (isEmptyMap && uiState.isOpen && !uiState.isLoading && !uiState.hasError) {
609
- loadData();
610
- }
611
- }, [uiState.isOpen, isEmptyMap, uiState.isLoading, uiState.hasError, loadData]);
612
593
  (0, react_1.useEffect)(() => {
613
594
  const step = uiState.step;
614
595
  if (step !== groupsFilterInterfaces_1.FilterMenuStep.CurrentlySelected) {
@@ -849,6 +830,41 @@ const GroupsFilterRaw = props => {
849
830
  children: translate("Clear")
850
831
  })]
851
832
  }), [handleApply, handleCancel, handleReset, isApplyDisabled, translate]);
833
+ const isEmptyMap = dataItems.length === 0;
834
+ (0, react_1.useEffect)(() => {
835
+ if (isEmptyMap && uiState.isOpen && !uiState.isLoading && !uiState.hasError) {
836
+ dispatchUiState({
837
+ type: uiStateActionType_1.UiStateActionType.SetLoadWithError,
838
+ payload: {
839
+ hasError: false,
840
+ isLoading: true
841
+ }
842
+ });
843
+ dataLoader().then(groups => {
844
+ dispatchState({
845
+ type: stateActionType_1.StateActionType.CreateGroupsMap,
846
+ payload: groups
847
+ });
848
+ dispatchUiState({
849
+ type: uiStateActionType_1.UiStateActionType.SetLoadWithError,
850
+ payload: {
851
+ hasError: false,
852
+ isLoading: false
853
+ }
854
+ });
855
+ setDataItems(groups);
856
+ }).catch(e => {
857
+ dispatchUiState({
858
+ type: uiStateActionType_1.UiStateActionType.SetLoadWithError,
859
+ payload: {
860
+ hasError: true,
861
+ isLoading: false
862
+ }
863
+ });
864
+ errorHandler(e);
865
+ });
866
+ }
867
+ }, [uiState.isOpen, isEmptyMap, uiState.isLoading, uiState.hasError, dataLoader, errorHandler]);
852
868
  const memoizedMobileView = (0, react_1.useMemo)(() => (0, jsx_runtime_1.jsxs)(mobileSheet_1.MobileSheet, {
853
869
  label: translate("Organization groups filter"),
854
870
  triggerRef: triggerRef,
@@ -84,9 +84,9 @@ const dialogHelpers_1 = require("../dialog/dialogHelpers");
84
84
  const themeContext_1 = require("../utils/theme/themeContext");
85
85
  const modalHelpers_1 = require("./modalHelpers");
86
86
  const textIconButton_1 = require("../textIconButton/textIconButton");
87
- const usePortal_1 = require("../commonHelpers/hooks/usePortal");
88
87
  const useClientReady_1 = require("../commonHelpers/hooks/useClientReady");
89
88
  const zen_1 = require("../utils/zen");
89
+ const react_dom_1 = require("react-dom");
90
90
  const Modal = ({
91
91
  isOpen,
92
92
  children,
@@ -101,8 +101,6 @@ const Modal = ({
101
101
  }) => {
102
102
  var _a, _b, _c;
103
103
  const lastActiveOutsideElement = (0, react_1.useRef)((_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.activeElement);
104
- // eslint-disable-next-line
105
- const modalRoot = ((_b = zen_1.zen === null || zen_1.zen === void 0 ? void 0 : zen_1.zen.document) === null || _b === void 0 ? void 0 : _b.fullscreenElement) || ((_c = zen_1.zen === null || zen_1.zen === void 0 ? void 0 : zen_1.zen.document) === null || _c === void 0 ? void 0 : _c.body);
106
104
  const [top, setTop] = (0, react_1.useState)(`${zen_1.zen.pageYOffset || 0}px`);
107
105
  const {
108
106
  dark
@@ -190,11 +188,11 @@ const Modal = ({
190
188
  onClick: onOutSideClick
191
189
  })]
192
190
  }), [darkClass, modalContainerClassName, labeledId, top, onClose, maxWidth, title, className, type, focus, modalContent, onOutSideClick]);
193
- const modalPortal = (0, usePortal_1.usePortal)(dialogHTML(labeledId), isOpen ? modalRoot : undefined);
194
191
  if (!isOpen || !isClientReady) {
195
192
  return null;
196
193
  }
197
- return modalPortal;
194
+ const modalRoot = ((_b = zen_1.zen.document) === null || _b === void 0 ? void 0 : _b.fullscreenElement) || ((_c = zen_1.zen.document) === null || _c === void 0 ? void 0 : _c.body);
195
+ return (0, react_dom_1.createPortal)(dialogHTML(labeledId), modalRoot);
198
196
  };
199
197
  exports.Modal = Modal;
200
198
  const dummyOnClose = () => {};
@@ -217,10 +215,10 @@ const DialogContentNew = ({
217
215
  const lastActiveOutsideElement = (0, react_1.useRef)((_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.activeElement);
218
216
  const iconDriveClassName = (0, useDriveClassName_1.useDriveClassName)("icon");
219
217
  const iconsByType = (0, react_1.useMemo)(() => ({
220
- "error": iconException_1.IconException,
221
- "success": iconCheckRadio_1.IconCheckRadio,
222
- "warning": iconWarning_1.IconWarning,
223
- "info": iconInfoCircle_1.IconInfoCircle
218
+ error: iconException_1.IconException,
219
+ success: iconCheckRadio_1.IconCheckRadio,
220
+ warning: iconWarning_1.IconWarning,
221
+ info: iconInfoCircle_1.IconInfoCircle
224
222
  }), []);
225
223
  const subscriptionCondition = (0, react_1.useCallback)(trigger => trigger.current !== null, []);
226
224
  (0, useTrapFocus_1.useTrapFocus)(contentRef, undefined, contentRef, subscriptionCondition);
@@ -295,8 +295,13 @@ export const GroupsFilterRaw = props => {
295
295
  const prevSearchField = useRef("");
296
296
  const groupsFilterId = useId();
297
297
  const popupId = useId();
298
- const isDataLoadedRef = useRef(false);
299
298
  const blocksMap = useMemo(() => [["builtInGroups", "userGroups"], ["advancedGroups", "builtInGroups", "userGroups"], ["builtInGroups", "userGroups"]], []);
299
+ const onOptionsToggle = useCallback(() => {
300
+ dispatchUiState({
301
+ type: UiStateActionType.ToggleOpen,
302
+ payload: undefined
303
+ });
304
+ }, []);
300
305
  const handleSetStep = useCallback(newStep => {
301
306
  var _a;
302
307
  uiState.step !== FilterMenuStep.CurrentlySelected && dispatchUiState({
@@ -545,8 +550,7 @@ export const GroupsFilterRaw = props => {
545
550
  errorHandler(e);
546
551
  return [];
547
552
  }), [dataLoader, errorHandler]);
548
- const loadData = useCallback(() => {
549
- isDataLoadedRef.current = true;
553
+ useEffect(() => {
550
554
  dispatchUiState({
551
555
  type: UiStateActionType.SetLoadWithError,
552
556
  payload: {
@@ -575,32 +579,9 @@ export const GroupsFilterRaw = props => {
575
579
  isLoading: false
576
580
  }
577
581
  });
578
- isDataLoadedRef.current = false;
579
582
  errorHandler(e);
580
583
  });
581
584
  }, [dataLoader, errorHandler]);
582
- useEffect(() => {
583
- if (isDataLoadedRef.current) {
584
- return;
585
- }
586
- loadData();
587
- }, [loadData]);
588
- const onOptionsToggle = useCallback(() => {
589
- const willBeOpen = !uiState.isOpen;
590
- dispatchUiState({
591
- type: UiStateActionType.ToggleOpen,
592
- payload: undefined
593
- });
594
- if (willBeOpen && !isDataLoadedRef.current && !uiState.isLoading) {
595
- loadData();
596
- }
597
- }, [uiState.isOpen, uiState.isLoading, loadData]);
598
- const isEmptyMap = dataItems.length === 0;
599
- useEffect(() => {
600
- if (isEmptyMap && uiState.isOpen && !uiState.isLoading && !uiState.hasError) {
601
- loadData();
602
- }
603
- }, [uiState.isOpen, isEmptyMap, uiState.isLoading, uiState.hasError, loadData]);
604
585
  useEffect(() => {
605
586
  const step = uiState.step;
606
587
  if (step !== FilterMenuStep.CurrentlySelected) {
@@ -841,6 +822,41 @@ export const GroupsFilterRaw = props => {
841
822
  children: translate("Clear")
842
823
  })]
843
824
  }), [handleApply, handleCancel, handleReset, isApplyDisabled, translate]);
825
+ const isEmptyMap = dataItems.length === 0;
826
+ useEffect(() => {
827
+ if (isEmptyMap && uiState.isOpen && !uiState.isLoading && !uiState.hasError) {
828
+ dispatchUiState({
829
+ type: UiStateActionType.SetLoadWithError,
830
+ payload: {
831
+ hasError: false,
832
+ isLoading: true
833
+ }
834
+ });
835
+ dataLoader().then(groups => {
836
+ dispatchState({
837
+ type: StateActionType.CreateGroupsMap,
838
+ payload: groups
839
+ });
840
+ dispatchUiState({
841
+ type: UiStateActionType.SetLoadWithError,
842
+ payload: {
843
+ hasError: false,
844
+ isLoading: false
845
+ }
846
+ });
847
+ setDataItems(groups);
848
+ }).catch(e => {
849
+ dispatchUiState({
850
+ type: UiStateActionType.SetLoadWithError,
851
+ payload: {
852
+ hasError: true,
853
+ isLoading: false
854
+ }
855
+ });
856
+ errorHandler(e);
857
+ });
858
+ }
859
+ }, [uiState.isOpen, isEmptyMap, uiState.isLoading, uiState.hasError, dataLoader, errorHandler]);
844
860
  const memoizedMobileView = useMemo(() => _jsxs(MobileSheet, {
845
861
  label: translate("Organization groups filter"),
846
862
  triggerRef: triggerRef,
@@ -19,9 +19,9 @@ import { isFocusable } from "../dialog/dialogHelpers";
19
19
  import { themeContext } from "../utils/theme/themeContext";
20
20
  import { getPredefinedFocusableItem } from "./modalHelpers";
21
21
  import { TextIconButton } from "../textIconButton/textIconButton";
22
- import { usePortal } from "../commonHelpers/hooks/usePortal";
23
22
  import { useClientReady } from "../commonHelpers/hooks/useClientReady";
24
23
  import { zen } from "../utils/zen";
24
+ import { createPortal } from "react-dom";
25
25
  injectString("cs", "Close", "Zav\u0159\xEDt");
26
26
  injectString("da-DK", "Close", "Luk");
27
27
  injectString("de", "Close", "Schlie\xDFen");
@@ -62,8 +62,6 @@ export const Modal = ({
62
62
  }) => {
63
63
  var _a, _b, _c;
64
64
  const lastActiveOutsideElement = useRef((_a = zen.document) === null || _a === void 0 ? void 0 : _a.activeElement);
65
- // eslint-disable-next-line
66
- const modalRoot = ((_b = zen === null || zen === void 0 ? void 0 : zen.document) === null || _b === void 0 ? void 0 : _b.fullscreenElement) || ((_c = zen === null || zen === void 0 ? void 0 : zen.document) === null || _c === void 0 ? void 0 : _c.body);
67
65
  const [top, setTop] = useState(`${zen.pageYOffset || 0}px`);
68
66
  const {
69
67
  dark
@@ -151,11 +149,11 @@ export const Modal = ({
151
149
  onClick: onOutSideClick
152
150
  })]
153
151
  }), [darkClass, modalContainerClassName, labeledId, top, onClose, maxWidth, title, className, type, focus, modalContent, onOutSideClick]);
154
- const modalPortal = usePortal(dialogHTML(labeledId), isOpen ? modalRoot : undefined);
155
152
  if (!isOpen || !isClientReady) {
156
153
  return null;
157
154
  }
158
- return modalPortal;
155
+ const modalRoot = ((_b = zen.document) === null || _b === void 0 ? void 0 : _b.fullscreenElement) || ((_c = zen.document) === null || _c === void 0 ? void 0 : _c.body);
156
+ return createPortal(dialogHTML(labeledId), modalRoot);
159
157
  };
160
158
  const dummyOnClose = () => {};
161
159
  export const DialogContentNew = ({
@@ -177,10 +175,10 @@ export const DialogContentNew = ({
177
175
  const lastActiveOutsideElement = useRef((_a = zen.document) === null || _a === void 0 ? void 0 : _a.activeElement);
178
176
  const iconDriveClassName = useDriveClassName("icon");
179
177
  const iconsByType = useMemo(() => ({
180
- "error": IconException,
181
- "success": IconCheckRadio,
182
- "warning": IconWarning,
183
- "info": IconInfoCircle
178
+ error: IconException,
179
+ success: IconCheckRadio,
180
+ warning: IconWarning,
181
+ info: IconInfoCircle
184
182
  }), []);
185
183
  const subscriptionCondition = useCallback(trigger => trigger.current !== null, []);
186
184
  useTrapFocus(contentRef, undefined, contentRef, subscriptionCondition);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geotab/zenith",
3
- "version": "3.6.0-beta.6",
3
+ "version": "3.6.0-beta.7",
4
4
  "description": "Zenith components library on React",
5
5
  "main": "dist/index.js",
6
6
  "types": "esm/index.d.ts",