@geotab/zenith 3.15.0 → 3.16.0-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 (184) hide show
  1. package/dist/absolute/absolute.js +1 -1
  2. package/dist/betaPill/betaPill.js +9 -9
  3. package/dist/commonHelpers/arrowNavigation/arrowNavigationHelper.d.ts +1 -0
  4. package/dist/commonHelpers/arrowNavigation/arrowNavigationHelper.js +5 -1
  5. package/dist/commonHelpers/hooks/useTrapFocus.d.ts +9 -0
  6. package/dist/commonHelpers/hooks/useTrapFocus.js +66 -14
  7. package/dist/controlledPopup/controlledPopup.d.ts +1 -1
  8. package/dist/controlledPopup/controlledPopup.js +1 -1
  9. package/dist/dropdownRaw/dropdownSearchableTrigger.js +1 -1
  10. package/dist/filtersBar/components/filtersBarRange/filtersBarRange.d.ts +1 -1
  11. package/dist/filtersBar/filtersBarSidePanel/components/filtersBarSidePanelRange/filtersBarSidePanelRange.d.ts +1 -1
  12. package/dist/filtersBar/filtersBarSidePanel/components/filtersBarSidePanelRange/filtersBarSidePanelRange.js +8 -5
  13. package/dist/filtersBar/filtersContainer/filtersContainer.js +7 -4
  14. package/dist/header/header.js +9 -2
  15. package/dist/header/headerHelpers.js +8 -5
  16. package/dist/index.css +142 -11
  17. package/dist/index.d.ts +6 -1
  18. package/dist/index.js +12 -3
  19. package/dist/modal/modal.d.ts +48 -0
  20. package/dist/modal/modal.js +37 -7
  21. package/dist/nav/navHeader/navHeader.d.ts +1 -1
  22. package/dist/nav/navHeader/navHeaderSearch/navHeaderSearch.js +1 -1
  23. package/dist/nav/navItem/navItem.d.ts +15 -2
  24. package/dist/nav/navItem/navItem.js +49 -7
  25. package/dist/nav/utils/navUtils.d.ts +2 -2
  26. package/dist/pillExpandable/pillExpandable.js +6 -3
  27. package/dist/rangeRaw/components/rangeField.d.ts +2 -1
  28. package/dist/rangeRaw/components/rangeField.js +4 -3
  29. package/dist/rangeRaw/rangeRaw.js +8 -5
  30. package/dist/rangeRaw/types.d.ts +1 -0
  31. package/dist/sidePanel/sidePanel.js +3 -2
  32. package/dist/table/selectable/interfaces.d.ts +13 -0
  33. package/dist/table/selectable/useSelectableRows.js +46 -12
  34. package/dist/table/selectable/utils/calculateSelectionState.js +35 -0
  35. package/dist/table/selectable/utils/isRowChecked.js +12 -1
  36. package/dist/table/table.d.ts +2 -0
  37. package/dist/table/table.js +3 -1
  38. package/dist/tabs/tabs.js +14 -5
  39. package/dist/textInputRaw/textInputRaw.js +1 -1
  40. package/dist/textInputRaw/types.d.ts +1 -0
  41. package/dist/tooltip/components/inlineTrigger.d.ts +43 -0
  42. package/dist/tooltip/components/inlineTrigger.js +42 -0
  43. package/dist/tooltip/tooltip.d.ts +5 -2
  44. package/dist/tooltip/tooltip.js +15 -4
  45. package/dist/trendIndicator/trendIndicator.d.ts +47 -0
  46. package/dist/trendIndicator/trendIndicator.js +47 -0
  47. package/dist/trendIndicator/trendIndicatorUtils.d.ts +9 -0
  48. package/dist/trendIndicator/trendIndicatorUtils.js +18 -0
  49. package/dist/utils/experimentalFeatures/experimentalContext.d.ts +17 -0
  50. package/dist/utils/experimentalFeatures/experimentalContext.js +29 -0
  51. package/dist/utils/experimentalFeatures/index.d.ts +4 -0
  52. package/dist/utils/experimentalFeatures/index.js +9 -0
  53. package/dist/utils/experimentalFeatures/registry.d.ts +13 -0
  54. package/dist/utils/experimentalFeatures/registry.js +11 -0
  55. package/dist/utils/experimentalFeatures/useExperimentalFeature.d.ts +3 -0
  56. package/dist/utils/experimentalFeatures/useExperimentalFeature.js +25 -0
  57. package/dist/utils/localization/translations/ar.json +1 -1
  58. package/dist/utils/localization/translations/bg-BG.json +1 -1
  59. package/dist/utils/localization/translations/cs.json +1 -1
  60. package/dist/utils/localization/translations/da-DK.json +1 -1
  61. package/dist/utils/localization/translations/de.json +1 -1
  62. package/dist/utils/localization/translations/el-GR.json +1 -1
  63. package/dist/utils/localization/translations/en.json +1 -1
  64. package/dist/utils/localization/translations/es.json +1 -1
  65. package/dist/utils/localization/translations/et-EE.json +1 -1
  66. package/dist/utils/localization/translations/fi-FI.json +1 -1
  67. package/dist/utils/localization/translations/fr-FR.json +1 -1
  68. package/dist/utils/localization/translations/fr.json +1 -1
  69. package/dist/utils/localization/translations/hu-HU.json +1 -1
  70. package/dist/utils/localization/translations/id.json +1 -1
  71. package/dist/utils/localization/translations/it.json +1 -1
  72. package/dist/utils/localization/translations/ja.json +1 -1
  73. package/dist/utils/localization/translations/ka-GE.json +1 -1
  74. package/dist/utils/localization/translations/ko-KR.json +1 -1
  75. package/dist/utils/localization/translations/lt-LT.json +1 -1
  76. package/dist/utils/localization/translations/lv-LV.json +1 -1
  77. package/dist/utils/localization/translations/ms.json +1 -1
  78. package/dist/utils/localization/translations/nb-NO.json +1 -1
  79. package/dist/utils/localization/translations/nl.json +1 -1
  80. package/dist/utils/localization/translations/pl.json +1 -1
  81. package/dist/utils/localization/translations/pt-BR.json +1 -1
  82. package/dist/utils/localization/translations/pt-PT.json +1 -1
  83. package/dist/utils/localization/translations/ro-RO.json +1 -1
  84. package/dist/utils/localization/translations/sk-SK.json +1 -1
  85. package/dist/utils/localization/translations/sv.json +1 -1
  86. package/dist/utils/localization/translations/th.json +1 -1
  87. package/dist/utils/localization/translations/tr.json +1 -1
  88. package/dist/utils/localization/translations/zh-Hans.json +1 -1
  89. package/dist/utils/localization/translations/zh-TW.json +1 -1
  90. package/esm/absolute/absolute.js +1 -1
  91. package/esm/betaPill/betaPill.js +9 -9
  92. package/esm/commonHelpers/arrowNavigation/arrowNavigationHelper.d.ts +1 -0
  93. package/esm/commonHelpers/arrowNavigation/arrowNavigationHelper.js +3 -0
  94. package/esm/commonHelpers/hooks/useTrapFocus.d.ts +9 -0
  95. package/esm/commonHelpers/hooks/useTrapFocus.js +67 -15
  96. package/esm/controlledPopup/controlledPopup.d.ts +1 -1
  97. package/esm/controlledPopup/controlledPopup.js +1 -1
  98. package/esm/dropdownRaw/dropdownSearchableTrigger.js +1 -1
  99. package/esm/filtersBar/components/filtersBarRange/filtersBarRange.d.ts +1 -1
  100. package/esm/filtersBar/filtersBarSidePanel/components/filtersBarSidePanelRange/filtersBarSidePanelRange.d.ts +1 -1
  101. package/esm/filtersBar/filtersBarSidePanel/components/filtersBarSidePanelRange/filtersBarSidePanelRange.js +8 -5
  102. package/esm/filtersBar/filtersContainer/filtersContainer.js +7 -4
  103. package/esm/header/header.js +9 -2
  104. package/esm/header/headerHelpers.js +8 -5
  105. package/esm/index.d.ts +6 -1
  106. package/esm/index.js +5 -1
  107. package/esm/modal/modal.d.ts +48 -0
  108. package/esm/modal/modal.js +37 -7
  109. package/esm/nav/navHeader/navHeader.d.ts +1 -1
  110. package/esm/nav/navHeader/navHeaderSearch/navHeaderSearch.js +1 -1
  111. package/esm/nav/navItem/navItem.d.ts +15 -2
  112. package/esm/nav/navItem/navItem.js +49 -7
  113. package/esm/nav/utils/navUtils.d.ts +2 -2
  114. package/esm/pillExpandable/pillExpandable.js +6 -3
  115. package/esm/rangeRaw/components/rangeField.d.ts +2 -1
  116. package/esm/rangeRaw/components/rangeField.js +4 -3
  117. package/esm/rangeRaw/rangeRaw.js +8 -5
  118. package/esm/rangeRaw/types.d.ts +1 -0
  119. package/esm/sidePanel/sidePanel.js +3 -2
  120. package/esm/table/selectable/interfaces.d.ts +13 -0
  121. package/esm/table/selectable/useSelectableRows.js +46 -12
  122. package/esm/table/selectable/utils/calculateSelectionState.js +35 -0
  123. package/esm/table/selectable/utils/isRowChecked.js +12 -1
  124. package/esm/table/table.d.ts +2 -0
  125. package/esm/table/table.js +2 -0
  126. package/esm/tabs/tabs.js +14 -5
  127. package/esm/testHelpers/renderWithFeatures.d.ts +4 -0
  128. package/esm/testHelpers/renderWithFeatures.js +6 -0
  129. package/esm/textInputRaw/textInputRaw.js +1 -1
  130. package/esm/textInputRaw/types.d.ts +1 -0
  131. package/esm/tooltip/components/inlineTrigger.d.ts +43 -0
  132. package/esm/tooltip/components/inlineTrigger.js +38 -0
  133. package/esm/tooltip/tooltip.d.ts +5 -2
  134. package/esm/tooltip/tooltip.js +15 -4
  135. package/esm/trendIndicator/trendIndicator.d.ts +47 -0
  136. package/esm/trendIndicator/trendIndicator.js +43 -0
  137. package/esm/trendIndicator/trendIndicatorUtils.d.ts +9 -0
  138. package/esm/trendIndicator/trendIndicatorUtils.js +14 -0
  139. package/esm/utils/experimentalFeatures/experimentalContext.d.ts +17 -0
  140. package/esm/utils/experimentalFeatures/experimentalContext.js +25 -0
  141. package/esm/utils/experimentalFeatures/index.d.ts +4 -0
  142. package/esm/utils/experimentalFeatures/index.js +3 -0
  143. package/esm/utils/experimentalFeatures/registry.d.ts +13 -0
  144. package/esm/utils/experimentalFeatures/registry.js +8 -0
  145. package/esm/utils/experimentalFeatures/useExperimentalFeature.d.ts +3 -0
  146. package/esm/utils/experimentalFeatures/useExperimentalFeature.js +21 -0
  147. package/esm/utils/localization/translations/ar.json +1 -1
  148. package/esm/utils/localization/translations/bg-BG.json +1 -1
  149. package/esm/utils/localization/translations/cs.json +1 -1
  150. package/esm/utils/localization/translations/da-DK.json +1 -1
  151. package/esm/utils/localization/translations/de.json +1 -1
  152. package/esm/utils/localization/translations/el-GR.json +1 -1
  153. package/esm/utils/localization/translations/en.json +1 -1
  154. package/esm/utils/localization/translations/es.json +1 -1
  155. package/esm/utils/localization/translations/et-EE.json +1 -1
  156. package/esm/utils/localization/translations/fi-FI.json +1 -1
  157. package/esm/utils/localization/translations/fr-FR.json +1 -1
  158. package/esm/utils/localization/translations/fr.json +1 -1
  159. package/esm/utils/localization/translations/hu-HU.json +1 -1
  160. package/esm/utils/localization/translations/id.json +1 -1
  161. package/esm/utils/localization/translations/it.json +1 -1
  162. package/esm/utils/localization/translations/ja.json +1 -1
  163. package/esm/utils/localization/translations/ka-GE.json +1 -1
  164. package/esm/utils/localization/translations/ko-KR.json +1 -1
  165. package/esm/utils/localization/translations/lt-LT.json +1 -1
  166. package/esm/utils/localization/translations/lv-LV.json +1 -1
  167. package/esm/utils/localization/translations/ms.json +1 -1
  168. package/esm/utils/localization/translations/nb-NO.json +1 -1
  169. package/esm/utils/localization/translations/nl.json +1 -1
  170. package/esm/utils/localization/translations/pl.json +1 -1
  171. package/esm/utils/localization/translations/pt-BR.json +1 -1
  172. package/esm/utils/localization/translations/pt-PT.json +1 -1
  173. package/esm/utils/localization/translations/ro-RO.json +1 -1
  174. package/esm/utils/localization/translations/sk-SK.json +1 -1
  175. package/esm/utils/localization/translations/sv.json +1 -1
  176. package/esm/utils/localization/translations/th.json +1 -1
  177. package/esm/utils/localization/translations/tr.json +1 -1
  178. package/esm/utils/localization/translations/zh-Hans.json +1 -1
  179. package/esm/utils/localization/translations/zh-TW.json +1 -1
  180. package/package.json +36 -16
  181. package/dist/banner/utils/isBannerTarget.d.ts +0 -1
  182. package/dist/banner/utils/isBannerTarget.js +0 -11
  183. package/esm/banner/utils/isBannerTarget.d.ts +0 -1
  184. package/esm/banner/utils/isBannerTarget.js +0 -7
@@ -3,6 +3,41 @@ export const calculateSelectionState = (entities, selections, all, checkboxVisib
3
3
  if (selections.size === 0) {
4
4
  return all ? SelectionState.All : SelectionState.None;
5
5
  }
6
+ if (all) {
7
+ // When `all` is true, `selections` holds the ids explicitly excluded from the
8
+ // otherwise-fully-selected set (see ISelectionValue), rather than included ids.
9
+ const isExcluded = (entity) => {
10
+ if (strategy === "nested" && entity.children) {
11
+ if (entity.children.length === 0) {
12
+ return false;
13
+ }
14
+ return entity.children.every(child => {
15
+ if (!checkboxVisible(child)) {
16
+ return true;
17
+ }
18
+ if (checkboxDisabled(child)) {
19
+ return true;
20
+ }
21
+ return selections.has(child.id);
22
+ });
23
+ }
24
+ return selections.has(entity.id);
25
+ };
26
+ const isPartiallyExcluded = (entity) => {
27
+ if (strategy === "nested" && entity.children) {
28
+ return entity.children.some(child => selections.has(child.id));
29
+ }
30
+ return selections.has(entity.id);
31
+ };
32
+ const relevantEntities = entities.filter(entity => checkboxVisible(entity) && !checkboxDisabled(entity));
33
+ if (relevantEntities.length === 0) {
34
+ return SelectionState.All;
35
+ }
36
+ if (relevantEntities.every(entity => !isPartiallyExcluded(entity))) {
37
+ return SelectionState.All;
38
+ }
39
+ return relevantEntities.every(entity => isExcluded(entity)) ? SelectionState.None : SelectionState.Partial;
40
+ }
6
41
  return entities.every(entity => {
7
42
  if (!checkboxVisible(entity)) {
8
43
  return true;
@@ -1,7 +1,18 @@
1
1
  import { SelectionState } from "../interfaces";
2
2
  export const isRowChecked = (selections, state, strategy, entity, isNested) => {
3
3
  if (state === SelectionState.All) {
4
- return { indeterminate: false, checked: true };
4
+ // When the overall selection is "all", `selections` holds the ids that have been
5
+ // explicitly excluded from that selection (see ISelectionValue), not included ids.
6
+ if (isNested) {
7
+ return { indeterminate: false, checked: !selections.has(entity.id) };
8
+ }
9
+ const mainEntity = entity;
10
+ if (strategy === "nested" && mainEntity.children && mainEntity.children.length > 0) {
11
+ const allChildrenChecked = mainEntity.children.every(child => !selections.has(child.id));
12
+ const someChildrenChecked = mainEntity.children.some(child => !selections.has(child.id));
13
+ return { indeterminate: someChildrenChecked && !allChildrenChecked, checked: allChildrenChecked };
14
+ }
15
+ return { indeterminate: false, checked: !selections.has(entity.id) };
5
16
  }
6
17
  if (isNested) {
7
18
  return { indeterminate: false, checked: selections.has(entity.id) };
@@ -25,6 +25,7 @@ import { IRowEntity } from "../dataGrid/row/row";
25
25
  import { IEntityWithId } from "../commonHelpers/entity";
26
26
  import "../cardContainer/cardContainer.less";
27
27
  import { ITableDetailPanel } from "./children/tableDetailPanel";
28
+ import { ITrendIndicator } from "../trendIndicator/trendIndicator";
28
29
  export interface IListColumn<T extends IRowEntity<N>, N extends IEntityWithId = T> {
29
30
  readonly id: string;
30
31
  readonly title: string;
@@ -92,6 +93,7 @@ interface ITableComponents {
92
93
  BulkButton: React.FC<IBulkActionButton>;
93
94
  BulkLink: React.FC<IBulkActionLink>;
94
95
  DetailPanel: React.FC<ITableDetailPanel>;
96
+ TrendIndicator: React.FC<ITrendIndicator>;
95
97
  }
96
98
  declare const TableInner: <T extends IRowEntity<N>, N extends IEntityWithId = T>({ entities, columns, selectable, sortable, flexible, isLoading, loading, children, className, height, onFeedEnd, onScrollEnd, rowClassName, feedExpandable, expandedRows, onExpand, active, onClick }: ITable<T, N>) => import("react/jsx-runtime").JSX.Element;
97
99
  declare const Table: typeof TableInner & ITableComponents;
@@ -37,6 +37,7 @@ import { FeedExpandControl } from "../dataFeed/feedExpandControl/feedExpandContr
37
37
  import { getGridClasses } from "../gridLayout/utils/getGridClasses";
38
38
  import { useNestedRows } from "./nested/useNestedRows";
39
39
  import { TableDetailPanel } from "./children/tableDetailPanel";
40
+ import { TrendIndicator } from "../trendIndicator/trendIndicator";
40
41
  import { useLanguage } from "../utils/localization/useLanguage";
41
42
  // Interpolation placeholder used in the "{count} more rows loaded" translation key.
42
43
  // `translate()` has no interpolation overload, so the count is substituted at runtime via
@@ -402,4 +403,5 @@ Table.Fullscreen = TableFullscreen;
402
403
  Table.BulkButton = BulkActionButton;
403
404
  Table.BulkLink = BulkActionLink;
404
405
  Table.DetailPanel = TableDetailPanel;
406
+ Table.TrendIndicator = TrendIndicator;
405
407
  export { Table, getEmptySelection, ColumnSortDirection, getSortableValue, ActionsColumn, MainColumn, CheckboxColumn, ActionLinkColumn };
package/esm/tabs/tabs.js CHANGED
@@ -11,6 +11,7 @@ import { IconChevronLeft } from "../icons/iconChevronLeft";
11
11
  import { useDirectionalIcon } from "../utils/localization/useDirectionalIcon";
12
12
  import { ButtonIconPosition, TextIconButton } from "../textIconButton/textIconButton";
13
13
  import { tabsKeyboardHandler, tabsKeyboardTabHandler } from "../commonHelpers/tabsKeyboard";
14
+ import { getDirectionalScrollDelta } from "../commonHelpers/arrowNavigation/arrowNavigationHelper";
14
15
  import { useMobileClassName } from "../utils/theme/useMobileClassName";
15
16
  import "../utils/globalThisPolyfill";
16
17
  import { zen } from "../utils/zen";
@@ -89,13 +90,15 @@ const getScrollButtonType = (element, isRTL) => {
89
90
  return "";
90
91
  }
91
92
  if (isRTL) {
93
+ // scrollLeft is 0 at the start (right edge) and negative toward the end (left edge),
94
+ // so the button to offer is the mirror of the LTR case below.
92
95
  if (scrollLeft < -1 && scrollLeft > clientWidth - scrollWidth + 1) {
93
96
  return "both";
94
97
  }
95
98
  if (scrollLeft >= -1) {
96
- return "start";
99
+ return "end";
97
100
  }
98
- return "end";
101
+ return "start";
99
102
  }
100
103
  if (scrollLeft > 0 && scrollWidth > clientWidth + scrollLeft + 1) {
101
104
  return "both";
@@ -129,6 +132,7 @@ export const Tabs = ({
129
132
  const scrollableRef = useRef(null);
130
133
  const scrollRef = useRef(0);
131
134
  const focusableTabIdRef = useRef("");
135
+ const userInitiatedTabChangeRef = useRef(false);
132
136
  const handleButtonClick = e => {
133
137
  if (disabled) {
134
138
  return;
@@ -136,6 +140,7 @@ export const Tabs = ({
136
140
  const newState = e.currentTarget.id;
137
141
  focusableTabIdRef.current = newState;
138
142
  if (newState !== activeTabId) {
143
+ userInitiatedTabChangeRef.current = true;
139
144
  onTabChange(newState);
140
145
  }
141
146
  };
@@ -152,6 +157,7 @@ export const Tabs = ({
152
157
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
153
158
  if (target && target.id && tabs.some(tab => tab.id === target.id)) {
154
159
  focusableTabIdRef.current = target.id;
160
+ userInitiatedTabChangeRef.current = true;
155
161
  onTabChange(target.id);
156
162
  }
157
163
  return;
@@ -233,7 +239,10 @@ export const Tabs = ({
233
239
  const activeTab = scrollableRef.current.querySelector(`.zen-tab-item[id='${activeTabId}']`);
234
240
  if (activeTab instanceof HTMLElement) {
235
241
  focusableTabIdRef.current = activeTab.getAttribute("id") || "";
236
- // activeTab.focus();
242
+ if (userInitiatedTabChangeRef.current) {
243
+ userInitiatedTabChangeRef.current = false;
244
+ activeTab.focus();
245
+ }
237
246
  }
238
247
  }, [activeTabId]);
239
248
  return _jsx("div", {
@@ -249,7 +258,7 @@ export const Tabs = ({
249
258
  icon: ScrollStartIcon,
250
259
  type: "tertiary",
251
260
  iconPosition: ButtonIconPosition.Start,
252
- onClick: handleScrollButtonClick(scrollableRef.current, -scrollableStep),
261
+ onClick: handleScrollButtonClick(scrollableRef.current, getDirectionalScrollDelta(-scrollableStep, isRTL)),
253
262
  iconClasses: "zen-tabs__start-icon"
254
263
  })]
255
264
  }) : null, _jsx("div", {
@@ -282,7 +291,7 @@ export const Tabs = ({
282
291
  className: classNames(["zen-tabs__scroller", driveClassNameScroller || mobileClassNameScroller || "", "zen-tabs__end"]),
283
292
  icon: ScrollEndIcon,
284
293
  type: "tertiary",
285
- onClick: handleScrollButtonClick(scrollableRef.current, scrollableStep),
294
+ onClick: handleScrollButtonClick(scrollableRef.current, getDirectionalScrollDelta(scrollableStep, isRTL)),
286
295
  iconPosition: ButtonIconPosition.End
287
296
  })]
288
297
  }) : null]
@@ -0,0 +1,4 @@
1
+ import { ReactNode } from "react";
2
+ import { RenderResult } from "@testing-library/react";
3
+ import { ExperimentalFeatureId } from "../utils/experimentalFeatures/registry";
4
+ export declare const renderWithFeatures: (ui: ReactNode, features?: Partial<Record<ExperimentalFeatureId, boolean>>) => RenderResult;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render } from "@testing-library/react";
3
+ import { ZenithExperimentalProvider } from "../utils/experimentalFeatures/experimentalContext";
4
+ export const renderWithFeatures = (ui, features) => {
5
+ return render(_jsx(ZenithExperimentalProvider, { features: features, children: ui }));
6
+ };
@@ -18,6 +18,6 @@ export const TextInputRaw = (props) => {
18
18
  props.isError ? "zen-text-input--error" : ""
19
19
  ]), value: maxLength ? value.substring(0, maxLength) : value, placeholder: props.placeholder, disabled: disabled, onChange: onChange, onKeyDown: props.onKeyDown, onBlur: onBlur, maxLength: maxLength, autoComplete: props.autocomplete,
20
20
  // TODO: add tests
21
- min: min, max: max, "aria-labelledby": props.ariaLabelledby, "aria-label": props.ariaLabel, autoFocus: props.autoFocus, required: !!required, onFocus: props.onFocus, minLength: minLength, name: name, pattern: pattern, role: props.role, "aria-expanded": props.ariaExpanded === undefined ? undefined : props.ariaExpanded === "true" || props.ariaExpanded === true, "aria-haspopup": props.ariaHaspopup, "aria-controls": props.ariaControls, "aria-autocomplete": props.ariaAutocomplete, "aria-describedby": props.ariaDescribedby }));
21
+ min: min, max: max, step: props.step, "aria-labelledby": props.ariaLabelledby, "aria-label": props.ariaLabel, autoFocus: props.autoFocus, required: !!required, onFocus: props.onFocus, minLength: minLength, name: name, pattern: pattern, role: props.role, "aria-expanded": props.ariaExpanded === undefined ? undefined : props.ariaExpanded === "true" || props.ariaExpanded === true, "aria-haspopup": props.ariaHaspopup, "aria-controls": props.ariaControls, "aria-autocomplete": props.ariaAutocomplete, "aria-describedby": props.ariaDescribedby }));
22
22
  };
23
23
  TextInputRaw.displayName = "TextInputRaw";
@@ -31,6 +31,7 @@ export interface ITextInputDefaultRaw extends IZenComponentProps, ITextInputRawB
31
31
  onBlur?: React.FocusEventHandler<HTMLInputElement>;
32
32
  min?: number;
33
33
  max?: number;
34
+ step?: number | "any";
34
35
  minLength?: number;
35
36
  maxLength?: number;
36
37
  pattern?: RegExp;
@@ -0,0 +1,43 @@
1
+ import { ReactNode, Ref } from "react";
2
+ import "./inlineTrigger.less";
3
+ export interface IInlineTrigger {
4
+ /**
5
+ * The inline text that receives the dotted underline treatment.
6
+ *
7
+ * Accepts any `ReactNode`, but avoid placing interactive elements (buttons,
8
+ * links, inputs) inside — nesting interactive elements is invalid HTML and
9
+ * creates a poor keyboard and screen-reader experience.
10
+ *
11
+ * **For use within body-level text only.** Do not use inside headings, page
12
+ * titles, modal headers, or any non-body typographic context. Apply the
13
+ * desired body typography via `className` (e.g. `zen-body-s-700`).
14
+ */
15
+ children: ReactNode;
16
+ /** Additional CSS class names applied to the trigger button (e.g. a body typography class). */
17
+ className?: string;
18
+ ref?: Ref<HTMLButtonElement>;
19
+ }
20
+ /**
21
+ * `Tooltip.InlineTrigger` is an inline, dotted-underline trigger for the `Tooltip` component.
22
+ * Pass it as the `trigger` prop of a `Tooltip` to annotate a term within body text.
23
+ *
24
+ * The dotted underline uses the surrounding font colour (`currentColor`) at 15% thickness.
25
+ * The trigger inherits its typography from the surrounding text by default; pass a body
26
+ * typography class via `className` (e.g. `zen-body-s-700`, `zen-body-s-400-italic`) to override
27
+ * it explicitly. All interaction
28
+ * (hover, focus, keyboard, positioning) is handled by the parent `Tooltip` — this component only
29
+ * renders the trigger element and forwards the event handlers and `ref` that `Tooltip` injects.
30
+ *
31
+ * Set an accessible name via the parent `Tooltip`'s `triggerAriaLabel` prop when `children`
32
+ * contains no readable text (e.g. a purely decorative image or icon), so the button is not
33
+ * left without an accessible name (WCAG 4.1.2).
34
+ *
35
+ * @example
36
+ * <Tooltip alignment="top" trigger={<Tooltip.InlineTrigger className="zen-body-s-700">Inline text</Tooltip.InlineTrigger>}>
37
+ * The tooltip text.
38
+ * </Tooltip>
39
+ */
40
+ export declare const InlineTrigger: {
41
+ ({ children, className, ref, ...injectedProps }: IInlineTrigger): import("react/jsx-runtime").JSX.Element;
42
+ displayName: string;
43
+ };
@@ -0,0 +1,38 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ import { classNames } from "../../commonHelpers/classNames/classNames";
14
+ /**
15
+ * `Tooltip.InlineTrigger` is an inline, dotted-underline trigger for the `Tooltip` component.
16
+ * Pass it as the `trigger` prop of a `Tooltip` to annotate a term within body text.
17
+ *
18
+ * The dotted underline uses the surrounding font colour (`currentColor`) at 15% thickness.
19
+ * The trigger inherits its typography from the surrounding text by default; pass a body
20
+ * typography class via `className` (e.g. `zen-body-s-700`, `zen-body-s-400-italic`) to override
21
+ * it explicitly. All interaction
22
+ * (hover, focus, keyboard, positioning) is handled by the parent `Tooltip` — this component only
23
+ * renders the trigger element and forwards the event handlers and `ref` that `Tooltip` injects.
24
+ *
25
+ * Set an accessible name via the parent `Tooltip`'s `triggerAriaLabel` prop when `children`
26
+ * contains no readable text (e.g. a purely decorative image or icon), so the button is not
27
+ * left without an accessible name (WCAG 4.1.2).
28
+ *
29
+ * @example
30
+ * <Tooltip alignment="top" trigger={<Tooltip.InlineTrigger className="zen-body-s-700">Inline text</Tooltip.InlineTrigger>}>
31
+ * The tooltip text.
32
+ * </Tooltip>
33
+ */
34
+ export const InlineTrigger = (_a) => {
35
+ var { children, className = "", ref } = _a, injectedProps = __rest(_a, ["children", "className", "ref"]);
36
+ return (_jsx("button", Object.assign({}, injectedProps, { ref: ref, type: "button", className: classNames(["zen-tooltip-inline-trigger", className]), children: children })));
37
+ };
38
+ InlineTrigger.displayName = "InlineTrigger";
@@ -1,7 +1,8 @@
1
- import React, { PropsWithChildren, ReactElement } from "react";
1
+ import React, { FC, PropsWithChildren, ReactElement } from "react";
2
2
  import { IZenComponentProps } from "../commonHelpers/zenComponent";
3
3
  import "./tooltip.less";
4
4
  import { TAlignment } from "../absolute/absolute";
5
+ import { IInlineTrigger } from "./components/inlineTrigger";
5
6
  export type TooltipSize = "large" | "small" | "auto";
6
7
  export type TMobileView = "default" | "mobileSheet";
7
8
  interface ITooltip extends IZenComponentProps {
@@ -33,5 +34,7 @@ interface ITooltip extends IZenComponentProps {
33
34
  */
34
35
  mobileSheetTitle?: ReactElement | string;
35
36
  }
36
- export declare const Tooltip: ({ trigger, triggerClassName, triggerAriaLabel, className, alignment, children, mobileSheetTitle, mobileTitle }: ITooltip) => import("react/jsx-runtime").JSX.Element;
37
+ export declare const Tooltip: FC<ITooltip> & {
38
+ InlineTrigger: FC<IInlineTrigger>;
39
+ };
37
40
  export {};
@@ -19,6 +19,7 @@ import { IconInfoCircle } from "../icons/iconInfoCircle";
19
19
  import { useDrive } from "../utils/theme/useDrive";
20
20
  import { Shield } from "../shield/shield";
21
21
  import { zen } from "../utils/zen";
22
+ import { InlineTrigger } from "./components/inlineTrigger";
22
23
  injectString("cs", "Information", "Informace");
23
24
  injectString("da-DK", "Information", "Information");
24
25
  injectString("de", "Information", "Information");
@@ -161,6 +162,7 @@ const EventWrapper = ({
161
162
  const propsToApply = isCurrentDeviceDesktop ? desktopEvents : mobileEvents;
162
163
  return React.cloneElement(children, propsToApply);
163
164
  };
165
+ // eslint-disable-next-line @typescript-eslint/naming-convention
164
166
  export const Tooltip = ({
165
167
  trigger,
166
168
  triggerClassName,
@@ -193,7 +195,7 @@ export const Tooltip = ({
193
195
  const {
194
196
  dark
195
197
  } = useContext(themeContext);
196
- const tooltipAlignment = useMemo(() => isMobile ? "bottom" : alignment || (direction === "ltr" ? "right" : "left"), [isMobile, alignment, direction]);
198
+ const tooltipAlignment = useMemo(() => isMobile ? "bottom" : alignment || "end", [isMobile, alignment]);
197
199
  const normalizedTooltipAlignment = useMemo(() => normalizeLogicalAlignment(tooltipAlignment, direction), [tooltipAlignment, direction]);
198
200
  const TOOLTIP_ARROW_HEIGHT = useMemo(() => isMobile || isDrive ? 0 : 6, [isMobile, isDrive]);
199
201
  const tooltipAlignmentRef = useRef(normalizedTooltipAlignment);
@@ -231,9 +233,17 @@ export const Tooltip = ({
231
233
  }
232
234
  }
233
235
  }, [trigger === null || trigger === void 0 ? void 0 : trigger.props, deviceType]);
234
- const triggerCloneProps = useMemo(() => isTooltipVisible ? {
236
+ // Apply `triggerAriaLabel` to a `Tooltip.InlineTrigger` trigger (it has no `ariaLabel` prop
237
+ // of its own); the default info-icon trigger below handles `triggerAriaLabel` separately.
238
+ // An `aria-label` set directly on the `Tooltip.InlineTrigger` element takes priority over
239
+ // `triggerAriaLabel`, so we only fall back to `triggerAriaLabel` when the trigger has none.
240
+ const isInlineTrigger = (trigger === null || trigger === void 0 ? void 0 : trigger.type) === InlineTrigger;
241
+ const triggerOwnAriaLabel = trigger === null || trigger === void 0 ? void 0 : trigger.props["aria-label"];
242
+ const triggerCloneProps = useMemo(() => Object.assign(Object.assign({}, isTooltipVisible ? {
235
243
  "aria-describedby": tooltipId
236
- } : {}, [isTooltipVisible, tooltipId]);
244
+ } : {}), isInlineTrigger && triggerAriaLabel && !triggerOwnAriaLabel ? {
245
+ "aria-label": triggerAriaLabel
246
+ } : {}), [isTooltipVisible, tooltipId, isInlineTrigger, triggerAriaLabel, triggerOwnAriaLabel]);
237
247
  const tooltipTrigger = useMemo(() => trigger ? trigger : _jsx("button", {
238
248
  tabIndex: 0,
239
249
  type: "button",
@@ -446,4 +456,5 @@ export const Tooltip = ({
446
456
  return _jsxs(_Fragment, {
447
457
  children: [portal, triggerClone]
448
458
  });
449
- };
459
+ };
460
+ Tooltip.InlineTrigger = InlineTrigger;
@@ -0,0 +1,47 @@
1
+ import "./trendIndicator.less";
2
+ import { IZenComponentProps } from "../commonHelpers/zenComponent";
3
+ export type TTrendIndicatorDirection = "up" | "down" | "neutral";
4
+ export type TTrendIndicatorTone = "positive" | "negative" | "neutral";
5
+ export interface ITrendIndicator extends Pick<IZenComponentProps, "className"> {
6
+ /** Primary measured value displayed next to the direction icon, e.g. `"12.4km"`. */
7
+ value: string;
8
+ /**
9
+ * Change delta displayed after the value, e.g. `"+5%"` or `"+12km"`. When
10
+ * {@link ITrendIndicator.direction} is omitted, its sign determines the direction
11
+ * (and therefore the arrow and the default tone).
12
+ */
13
+ delta: string;
14
+ /**
15
+ * Trend direction — controls the arrow icon. When omitted, it is derived from the
16
+ * sign of {@link ITrendIndicator.delta}.
17
+ */
18
+ direction?: TTrendIndicatorDirection;
19
+ /**
20
+ * Color tone for the icon and delta. Defaults to the direction (`up` → positive,
21
+ * `down` → negative, `neutral` → neutral). Set it explicitly to decouple color from
22
+ * the arrow — e.g. `direction="up"` with `tone="negative"` for metrics where a rise
23
+ * is undesirable.
24
+ */
25
+ tone?: TTrendIndicatorTone;
26
+ }
27
+ /**
28
+ * A directional trend indicator: a direction icon, a value, and a change delta.
29
+ * Example: ▲ 12.4km +5%.
30
+ *
31
+ * Built for the `Table` and exposed only as `Table.TrendIndicator`, for use
32
+ * inside a column's inline `render` (or the table's mobile card form).
33
+ * Presentational — it conveys a value and its change and has no interactive
34
+ * behavior.
35
+ *
36
+ * The arrow icon reflects `direction`; the icon and delta take a color `tone`
37
+ * (positive / negative / neutral) from design tokens. Tone defaults to the
38
+ * direction but can be set independently for metrics where a rise is bad. The
39
+ * value uses the primary text color.
40
+ *
41
+ * The direction icon is decorative — direction is also conveyed by the sign of
42
+ * the delta text, so no accessible name is required.
43
+ */
44
+ export declare const TrendIndicator: {
45
+ ({ value, delta, direction, tone, className }: ITrendIndicator): import("react/jsx-runtime").JSX.Element;
46
+ displayName: string;
47
+ };
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { classNames } from "../commonHelpers/classNames/classNames";
3
+ import { IconChevronTopSmall } from "../icons/iconChevronTopSmall";
4
+ import { IconChevronDownSmall } from "../icons/iconChevronDownSmall";
5
+ import { IconTrendNeutral } from "../icons/iconTrendNeutral";
6
+ import { getTrendIndicatorDirection } from "./trendIndicatorUtils";
7
+ const DIRECTION_TONE = {
8
+ up: "positive",
9
+ down: "negative",
10
+ neutral: "neutral"
11
+ };
12
+ const DirectionIcon = ({ direction }) => {
13
+ if (direction === "down") {
14
+ return _jsx(IconChevronDownSmall, { className: "zen-trend-indicator__icon", size: "large" });
15
+ }
16
+ if (direction === "neutral") {
17
+ return _jsx(IconTrendNeutral, { className: "zen-trend-indicator__icon", size: "large" });
18
+ }
19
+ return _jsx(IconChevronTopSmall, { className: "zen-trend-indicator__icon", size: "large" });
20
+ };
21
+ /**
22
+ * A directional trend indicator: a direction icon, a value, and a change delta.
23
+ * Example: ▲ 12.4km +5%.
24
+ *
25
+ * Built for the `Table` and exposed only as `Table.TrendIndicator`, for use
26
+ * inside a column's inline `render` (or the table's mobile card form).
27
+ * Presentational — it conveys a value and its change and has no interactive
28
+ * behavior.
29
+ *
30
+ * The arrow icon reflects `direction`; the icon and delta take a color `tone`
31
+ * (positive / negative / neutral) from design tokens. Tone defaults to the
32
+ * direction but can be set independently for metrics where a rise is bad. The
33
+ * value uses the primary text color.
34
+ *
35
+ * The direction icon is decorative — direction is also conveyed by the sign of
36
+ * the delta text, so no accessible name is required.
37
+ */
38
+ export const TrendIndicator = ({ value, delta, direction, tone, className }) => {
39
+ const resolvedDirection = direction !== null && direction !== void 0 ? direction : getTrendIndicatorDirection(delta);
40
+ const resolvedTone = tone !== null && tone !== void 0 ? tone : DIRECTION_TONE[resolvedDirection];
41
+ return (_jsxs("span", { className: classNames(["zen-trend-indicator", `zen-trend-indicator--${resolvedTone}`, className !== null && className !== void 0 ? className : ""]), children: [_jsx(DirectionIcon, { direction: resolvedDirection }), _jsx("span", { className: "zen-trend-indicator__value", children: value }), _jsx("span", { className: "zen-trend-indicator__delta", children: delta })] }));
42
+ };
43
+ TrendIndicator.displayName = "TrendIndicator";
@@ -0,0 +1,9 @@
1
+ import type { TTrendIndicatorDirection } from "./trendIndicator";
2
+ /**
3
+ * Derives a {@link TTrendIndicatorDirection} from the sign of a delta string.
4
+ *
5
+ * Strips any non-numeric characters (currency symbols, `%`, units) before
6
+ * parsing, so inputs like `"+5%"`, `"-5%"`, and `"+0%"` are handled. A zero,
7
+ * empty, or unparsable delta resolves to `"neutral"`.
8
+ */
9
+ export declare const getTrendIndicatorDirection: (delta: string) => TTrendIndicatorDirection;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Derives a {@link TTrendIndicatorDirection} from the sign of a delta string.
3
+ *
4
+ * Strips any non-numeric characters (currency symbols, `%`, units) before
5
+ * parsing, so inputs like `"+5%"`, `"-5%"`, and `"+0%"` are handled. A zero,
6
+ * empty, or unparsable delta resolves to `"neutral"`.
7
+ */
8
+ export const getTrendIndicatorDirection = (delta) => {
9
+ const numeric = parseFloat(delta.replace(/[^0-9.+-]/g, ""));
10
+ if (Number.isNaN(numeric) || numeric === 0) {
11
+ return "neutral";
12
+ }
13
+ return numeric > 0 ? "up" : "down";
14
+ };
@@ -0,0 +1,17 @@
1
+ import { ReactNode } from "react";
2
+ import { ExperimentalFeatureId } from "./registry";
3
+ export type FeatureOverrides<TFeatureId extends string = ExperimentalFeatureId> = Partial<Record<TFeatureId, boolean>>;
4
+ type ContextFeatureOverrides = FeatureOverrides<string>;
5
+ interface IExperimentalContext {
6
+ features: ContextFeatureOverrides;
7
+ }
8
+ export declare const experimentalContext: import("react").Context<IExperimentalContext>;
9
+ interface IZenithExperimentalProviderProps {
10
+ features?: Partial<Record<ExperimentalFeatureId, boolean>>;
11
+ children: ReactNode;
12
+ }
13
+ export declare const ZenithExperimentalProvider: {
14
+ ({ features, children }: IZenithExperimentalProviderProps): import("react/jsx-runtime").JSX.Element;
15
+ displayName: string;
16
+ };
17
+ export {};
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useMemo } from "react";
3
+ import { experimentalFeatures, FeatureState } from "./registry";
4
+ const buildDefaultFeatures = () => {
5
+ const defaults = {};
6
+ for (const feature of experimentalFeatures) {
7
+ if (feature.state !== FeatureState.Killed) {
8
+ defaults[feature.id] = feature.state === FeatureState.Enabled;
9
+ }
10
+ }
11
+ return defaults;
12
+ };
13
+ const DEFAULT_FEATURES = buildDefaultFeatures();
14
+ const EMPTY_FEATURES = {};
15
+ export const experimentalContext = createContext({
16
+ features: {}
17
+ });
18
+ export const ZenithExperimentalProvider = ({ features = EMPTY_FEATURES, children }) => {
19
+ const parentContext = useContext(experimentalContext);
20
+ const contextValue = useMemo(() => ({
21
+ features: Object.assign(Object.assign(Object.assign({}, DEFAULT_FEATURES), parentContext.features), features)
22
+ }), [features, parentContext.features]);
23
+ return _jsx(experimentalContext.Provider, { value: contextValue, children: children });
24
+ };
25
+ ZenithExperimentalProvider.displayName = "ZenithExperimentalProvider";
@@ -0,0 +1,4 @@
1
+ export { EXPERIMENTAL_FLAGS } from "./registry";
2
+ export type { ExperimentalFeatureId } from "./registry";
3
+ export { ZenithExperimentalProvider } from "./experimentalContext";
4
+ export { useExperimentalFeature } from "./useExperimentalFeature";
@@ -0,0 +1,3 @@
1
+ export { EXPERIMENTAL_FLAGS } from "./registry";
2
+ export { ZenithExperimentalProvider } from "./experimentalContext";
3
+ export { useExperimentalFeature } from "./useExperimentalFeature";
@@ -0,0 +1,13 @@
1
+ export declare enum FeatureState {
2
+ Preview = 0,// OFF by default — consumers may opt in via provider/prop
3
+ Enabled = 1,// ON by default — consumers may opt out locally
4
+ Killed = 2
5
+ }
6
+ export interface IExperimentalFeatureDefinition {
7
+ id: string;
8
+ state: FeatureState;
9
+ description: string;
10
+ }
11
+ export declare const experimentalFeatures: readonly [];
12
+ export type ExperimentalFeatureId = (typeof experimentalFeatures)[number]["id"];
13
+ export declare const EXPERIMENTAL_FLAGS: { [K in ExperimentalFeatureId]: K; };
@@ -0,0 +1,8 @@
1
+ export var FeatureState;
2
+ (function (FeatureState) {
3
+ FeatureState[FeatureState["Preview"] = 0] = "Preview";
4
+ FeatureState[FeatureState["Enabled"] = 1] = "Enabled";
5
+ FeatureState[FeatureState["Killed"] = 2] = "Killed"; // OFF, locked — all overrides ignored; awaiting code deletion
6
+ })(FeatureState || (FeatureState = {}));
7
+ export const experimentalFeatures = [];
8
+ export const EXPERIMENTAL_FLAGS = Object.fromEntries(experimentalFeatures.map(({ id }) => [id, id]));
@@ -0,0 +1,3 @@
1
+ import { FeatureOverrides } from "./experimentalContext";
2
+ import { ExperimentalFeatureId } from "./registry";
3
+ export declare const useExperimentalFeature: (key: ExperimentalFeatureId, localOverrides?: FeatureOverrides) => boolean;
@@ -0,0 +1,21 @@
1
+ import { useContext } from "react";
2
+ import { experimentalContext } from "./experimentalContext";
3
+ import { experimentalFeatures, FeatureState } from "./registry";
4
+ const experimentalFeatureById = new Map(experimentalFeatures.map(feature => [feature.id, feature]));
5
+ const getFeatureOverride = (overrides, featureId) => overrides === null || overrides === void 0 ? void 0 : overrides[featureId];
6
+ export const useExperimentalFeature = (key, localOverrides) => {
7
+ const context = useContext(experimentalContext);
8
+ const feature = experimentalFeatureById.get(key);
9
+ if ((feature === null || feature === void 0 ? void 0 : feature.state) === FeatureState.Killed) {
10
+ return false;
11
+ }
12
+ const localOverride = getFeatureOverride(localOverrides, key);
13
+ if (localOverride !== undefined) {
14
+ return localOverride;
15
+ }
16
+ const contextOverride = context.features[key];
17
+ if (contextOverride !== undefined) {
18
+ return contextOverride;
19
+ }
20
+ return (feature === null || feature === void 0 ? void 0 : feature.state) === FeatureState.Enabled;
21
+ };
@@ -90,7 +90,7 @@
90
90
  "Go to My Reports": "الذهاب إلى تقاريري",
91
91
  "There was an issue preparing your report": "حدثت مشكلة في إعداد تقريرك",
92
92
  "Your report is being prepared": "يتم إعداد تقريرك",
93
- "We will notify you when your report is ready. You can track the progress by going to the My Reports page.": "سنخطرك عندما يصبح تقريرك جاهزًا. يمكنك تتبع التقدم بالذهاب إلى صفحة تقاريري.",
93
+ "You'll be notified when your report is ready. Track the progress on the My Reports page.": "سنخطرك عندما يصبح تقريرك جاهزًا. يمكنك تتبع التقدم بالذهاب إلى صفحة تقاريري.",
94
94
  "Your report is ready to download": "تقريرك جاهز للتنزيل",
95
95
  "Download now": "تنزيل الآن",
96
96
  "Download": "تنزيل",
@@ -92,7 +92,7 @@
92
92
  "Go to My Reports": "Към Моите отчети",
93
93
  "There was an issue preparing your report": "Възникна проблем при подготовката на вашия отчет",
94
94
  "Your report is being prepared": "Вашият отчет се подготвя",
95
- "We will notify you when your report is ready. You can track the progress by going to the My Reports page.": "Ще ви уведомим, когато отчетът е готов. Можете да проследите напредъка от страницата Моите отчети.",
95
+ "You'll be notified when your report is ready. Track the progress on the My Reports page.": "Ще ви уведомим, когато отчетът е готов. Можете да проследите напредъка от страницата Моите отчети.",
96
96
  "Your report is ready to download": "Вашият отчет е готов за изтегляне",
97
97
  "Download now": "Изтеглете сега",
98
98
  "Download": "Изтегляне",
@@ -81,7 +81,7 @@
81
81
  "All": "Vše",
82
82
  "There was an issue preparing your report": "Při připravování výkazu došlo k problému",
83
83
  "Your report is being prepared": "Váš výkaz se připravuje",
84
- "We will notify you when your report is ready. You can track the progress by going to the My Reports page.": "Až bude váš výkaz připraven, upozorníme vás. Průběh můžete sledovat na stránce Moje výkazy.",
84
+ "You'll be notified when your report is ready. Track the progress on the My Reports page.": "Až bude váš výkaz připraven, upozorníme vás. Průběh můžete sledovat na stránce Moje výkazy.",
85
85
  "Your report is ready to download": "Váš výkaz je připraven ke stažení",
86
86
  "Download now": "Stáhnout",
87
87
  "Download": "Stáhnout",
@@ -88,7 +88,7 @@
88
88
  "Go to My Reports": "Gå til Mine rapporter",
89
89
  "There was an issue preparing your report": "Der opstod et problem med at lave din rapport.",
90
90
  "Your report is being prepared": "Din rapport er ved at blive lavet.",
91
- "We will notify you when your report is ready. You can track the progress by going to the My Reports page.": "Vi giver dig besked, når din rapport er klar. Du kan tjekke status på siden 'Mine rapporter'.",
91
+ "You'll be notified when your report is ready. Track the progress on the My Reports page.": "Vi giver dig besked, når din rapport er klar. Du kan tjekke status på siden 'Mine rapporter'.",
92
92
  "Your report is ready to download": "Din rapport er klar til download",
93
93
  "Download now": "Download nu",
94
94
  "Download": "Download",