@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
package/dist/index.css CHANGED
@@ -2868,7 +2868,6 @@ html:lang(ar) .zen-accordion {
2868
2868
  }
2869
2869
  .zen-banner__content--multiline {
2870
2870
  flex-direction: column;
2871
- row-gap: 0.5rem;
2872
2871
  }
2873
2872
  .zen-banner__close-button {
2874
2873
  display: flex;
@@ -2912,6 +2911,8 @@ html:lang(ar) .zen-accordion {
2912
2911
  }
2913
2912
  .zen-banner__block--multiline {
2914
2913
  height: unset;
2914
+ flex-wrap: wrap;
2915
+ padding-block-end: 0.75rem;
2915
2916
  }
2916
2917
  .zen-banner__block--XXL {
2917
2918
  max-width: 100%;
@@ -2936,13 +2937,11 @@ html:lang(ar) .zen-accordion {
2936
2937
  max-width: 22.5rem;
2937
2938
  min-width: 16.75rem;
2938
2939
  }
2939
- .zen-banner__block--multiline {
2940
- flex-wrap: wrap;
2941
- }
2942
2940
  .zen-banner__multiline-container {
2943
2941
  display: flex;
2944
2942
  align-items: center;
2945
2943
  justify-content: space-between;
2944
+ min-height: 2rem;
2946
2945
  width: 100%;
2947
2946
  }
2948
2947
  .zen-banner__header-container {
@@ -3121,9 +3120,6 @@ html:lang(ar) .zen-banner__message--multiline {
3121
3120
  gap: 0.25rem;
3122
3121
  width: 100%;
3123
3122
  }
3124
- .zen-banner:has(.zen-banner__summary-error-list) .zen-banner__multiline-container {
3125
- min-height: 2rem;
3126
- }
3127
3123
  .zen-banner .zen-banner__summary-error-link {
3128
3124
  font-family: Roboto, "Segoe UI", Segoe, "Helvetica Neue", Helvetica, sans-serif;
3129
3125
  font-size: 0.875rem;
@@ -3403,6 +3399,29 @@ html:lang(ar) .zen-tooltip__title {
3403
3399
  .zen-shield-faded--visible {
3404
3400
  opacity: 0.1;
3405
3401
  }
3402
+ :where(.zen-tooltip-inline-trigger) {
3403
+ font: inherit;
3404
+ }
3405
+ .zen-tooltip-inline-trigger {
3406
+ display: inline;
3407
+ cursor: pointer;
3408
+ padding: 0;
3409
+ margin: 0;
3410
+ border: none;
3411
+ background: none;
3412
+ color: inherit;
3413
+ text-decoration: underline dotted;
3414
+ text-decoration-thickness: 15%;
3415
+ text-underline-offset: 0.25rem;
3416
+ border-radius: 0.125rem;
3417
+ outline-offset: 0.125rem;
3418
+ }
3419
+ .zen-tooltip-inline-trigger:focus-visible {
3420
+ outline: 0.125rem solid currentColor;
3421
+ }
3422
+ .zen-tooltip-inline-trigger:focus:not(:focus-visible) {
3423
+ outline: none;
3424
+ }
3406
3425
  .zen-tooltip-info {
3407
3426
  align-items: center;
3408
3427
  cursor: pointer;
@@ -4145,6 +4164,15 @@ html:lang(ar) .zen-side-panel {
4145
4164
  .zen-side-panel--shown .zen-form-field--new-component {
4146
4165
  display: flex;
4147
4166
  }
4167
+ .zen-side-panel--right-positioned {
4168
+ transform: translateX(100%);
4169
+ }
4170
+ [dir="rtl"] .zen-side-panel--right-positioned {
4171
+ transform: translateX(-100%);
4172
+ }
4173
+ .zen-side-panel.zen-side-panel--right-positioned.zen-side-panel--shown {
4174
+ transform: translateX(0);
4175
+ }
4148
4176
  .zen-side-panel--left-positioned {
4149
4177
  inset-inline-start: 0;
4150
4178
  inset-inline-end: auto;
@@ -4154,6 +4182,9 @@ html:lang(ar) .zen-side-panel {
4154
4182
  border-start-end-radius: var(--border-radius-default);
4155
4183
  border-end-end-radius: var(--border-radius-default);
4156
4184
  }
4185
+ [dir="rtl"] .zen-side-panel--left-positioned {
4186
+ transform: translateX(100%);
4187
+ }
4157
4188
  .zen-side-panel.zen-side-panel--left-positioned.zen-side-panel--shown {
4158
4189
  transform: translateX(0);
4159
4190
  }
@@ -6741,6 +6772,66 @@ html:lang(ar) .zen-table-number {
6741
6772
  .zen-feedExpandControl * {
6742
6773
  box-sizing: border-box;
6743
6774
  }
6775
+ .zen-trend-indicator {
6776
+ box-sizing: border-box;
6777
+ display: inline-flex;
6778
+ align-items: center;
6779
+ padding: 0.25rem 0;
6780
+ min-width: 0;
6781
+ max-width: 100%;
6782
+ }
6783
+ .zen-trend-indicator * {
6784
+ box-sizing: border-box;
6785
+ }
6786
+ .zen-trend-indicator__icon {
6787
+ flex-shrink: 0;
6788
+ }
6789
+ .zen-trend-indicator__value {
6790
+ font-family: Roboto, "Segoe UI", Segoe, "Helvetica Neue", Helvetica, sans-serif;
6791
+ font-size: 0.75rem;
6792
+ font-style: normal;
6793
+ font-weight: 400;
6794
+ letter-spacing: 0.02rem;
6795
+ line-height: 1rem;
6796
+ text-transform: none;
6797
+ text-decoration: none;
6798
+ overflow: hidden;
6799
+ text-overflow: ellipsis;
6800
+ white-space: nowrap;
6801
+ word-wrap: normal;
6802
+ color: var(--text-primary);
6803
+ min-width: 0;
6804
+ }
6805
+ html:lang(ar) .zen-trend-indicator__value {
6806
+ font-family: "Noto Sans Arabic", Roboto, "Segoe UI", Segoe, "Helvetica Neue", Helvetica, sans-serif;
6807
+ }
6808
+ .zen-trend-indicator__delta {
6809
+ font-family: Roboto, "Segoe UI", Segoe, "Helvetica Neue", Helvetica, sans-serif;
6810
+ font-size: 0.75rem;
6811
+ font-style: normal;
6812
+ font-weight: 400;
6813
+ letter-spacing: 0.02rem;
6814
+ line-height: 1rem;
6815
+ text-transform: none;
6816
+ text-decoration: none;
6817
+ flex-shrink: 0;
6818
+ margin-inline-start: 0.25rem;
6819
+ }
6820
+ html:lang(ar) .zen-trend-indicator__delta {
6821
+ font-family: "Noto Sans Arabic", Roboto, "Segoe UI", Segoe, "Helvetica Neue", Helvetica, sans-serif;
6822
+ }
6823
+ .zen-trend-indicator--positive .zen-trend-indicator__icon,
6824
+ .zen-trend-indicator--positive .zen-trend-indicator__delta {
6825
+ color: var(--accents-success--detail);
6826
+ }
6827
+ .zen-trend-indicator--negative .zen-trend-indicator__icon,
6828
+ .zen-trend-indicator--negative .zen-trend-indicator__delta {
6829
+ color: var(--accents-error--detail);
6830
+ }
6831
+ .zen-trend-indicator--neutral .zen-trend-indicator__icon,
6832
+ .zen-trend-indicator--neutral .zen-trend-indicator__delta {
6833
+ color: var(--text-secondary);
6834
+ }
6744
6835
  .zen-summary-tile {
6745
6836
  box-sizing: border-box;
6746
6837
  font-family: Roboto, "Segoe UI", Segoe, "Helvetica Neue", Helvetica, sans-serif;
@@ -7594,8 +7685,13 @@ html:lang(ar) .zen-pill-content {
7594
7685
  outline-offset: 2px;
7595
7686
  }
7596
7687
  .zen-pill-actionable__input {
7688
+ clip: rect(0 0 0 0);
7689
+ clip-path: inset(50%);
7690
+ height: 1px;
7691
+ overflow: hidden;
7597
7692
  position: absolute;
7598
- left: -5000px;
7693
+ white-space: nowrap;
7694
+ width: 1px;
7599
7695
  }
7600
7696
  .zen-pill-actionable__content-wrapper {
7601
7697
  margin: 0;
@@ -8650,8 +8746,13 @@ html:lang(ar) .zen-chip {
8650
8746
  cursor: pointer;
8651
8747
  }
8652
8748
  .zen-chip__input {
8749
+ clip: rect(0 0 0 0);
8750
+ clip-path: inset(50%);
8751
+ height: 1px;
8752
+ overflow: hidden;
8653
8753
  position: absolute;
8654
- left: -5000px;
8754
+ white-space: nowrap;
8755
+ width: 1px;
8655
8756
  }
8656
8757
  .zen-chip__content-wrapper {
8657
8758
  margin: 0;
@@ -15268,6 +15369,9 @@ html:lang(ar) .zen-page-header--mobile .zen-page-header__page-name {
15268
15369
  inset-inline-end: calc(2.25rem - 0.375rem);
15269
15370
  background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15270
15371
  }
15372
+ [dir="rtl"] .zen-tabs__gradient--right::before {
15373
+ background: linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15374
+ }
15271
15375
  .zen-tabs__gradient--right::after {
15272
15376
  position: absolute;
15273
15377
  content: "";
@@ -15295,6 +15399,9 @@ html:lang(ar) .zen-page-header--mobile .zen-page-header__page-name {
15295
15399
  inset-inline-start: calc(2.25rem - 0.375rem);
15296
15400
  background: linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15297
15401
  }
15402
+ [dir="rtl"] .zen-tabs__gradient--left::after {
15403
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15404
+ }
15298
15405
  .zen-tabs__start {
15299
15406
  margin-inline-end: 0.5rem;
15300
15407
  inset-block-end: 0;
@@ -15338,6 +15445,9 @@ html:lang(ar) .zen-page-header--mobile .zen-page-header__page-name {
15338
15445
  inset-inline-start: calc(2.875rem - 0.5rem);
15339
15446
  background: linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15340
15447
  }
15448
+ [dir="rtl"] .zen-tabs .zen-tabs__gradient.zen-tabs__gradient--mobile.zen-tabs__gradient--left::after {
15449
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15450
+ }
15341
15451
  .zen-tabs .zen-tabs__gradient.zen-tabs__gradient--mobile.zen-tabs__gradient--right::before {
15342
15452
  position: absolute;
15343
15453
  content: "";
@@ -15347,6 +15457,9 @@ html:lang(ar) .zen-page-header--mobile .zen-page-header__page-name {
15347
15457
  inset-inline-end: calc(2.875rem - 0.5rem);
15348
15458
  background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15349
15459
  }
15460
+ [dir="rtl"] .zen-tabs .zen-tabs__gradient.zen-tabs__gradient--mobile.zen-tabs__gradient--right::before {
15461
+ background: linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15462
+ }
15350
15463
  .zen-tabs.zen-tabs--drive,
15351
15464
  .zen-tabs.zen-tabs--drive-tablet {
15352
15465
  height: 3rem;
@@ -15366,6 +15479,10 @@ html:lang(ar) .zen-page-header--mobile .zen-page-header__page-name {
15366
15479
  inset-inline-start: calc(3rem - 0.5rem);
15367
15480
  background: linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15368
15481
  }
15482
+ [dir="rtl"] .zen-tabs .zen-tabs__gradient.zen-tabs__gradient--drive.zen-tabs__gradient--left::after,
15483
+ [dir="rtl"] .zen-tabs .zen-tabs__gradient.zen-tabs__gradient--drive-tablet.zen-tabs__gradient--left::after {
15484
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15485
+ }
15369
15486
  .zen-tabs .zen-tabs__gradient.zen-tabs__gradient--drive.zen-tabs__gradient--right::before,
15370
15487
  .zen-tabs .zen-tabs__gradient.zen-tabs__gradient--drive-tablet.zen-tabs__gradient--right::before {
15371
15488
  position: absolute;
@@ -15376,6 +15493,10 @@ html:lang(ar) .zen-page-header--mobile .zen-page-header__page-name {
15376
15493
  inset-inline-end: calc(3rem - 0.5rem);
15377
15494
  background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15378
15495
  }
15496
+ [dir="rtl"] .zen-tabs .zen-tabs__gradient.zen-tabs__gradient--drive.zen-tabs__gradient--right::before,
15497
+ [dir="rtl"] .zen-tabs .zen-tabs__gradient.zen-tabs__gradient--drive-tablet.zen-tabs__gradient--right::before {
15498
+ background: linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, var(--backgrounds-content-0) 100%);
15499
+ }
15379
15500
  .zen-tab-item {
15380
15501
  box-sizing: border-box;
15381
15502
  font-family: Roboto, "Segoe UI", Segoe, "Helvetica Neue", Helvetica, sans-serif;
@@ -15564,7 +15685,7 @@ html:lang(ar) .zen-tab-item.zen-tab-item--mobile .zen-tab-item__content-text {
15564
15685
  text-decoration: none;
15565
15686
  }
15566
15687
  .zen-tab-item:focus-visible {
15567
- outline: 1px solid var(--borders-form-field--active);
15688
+ outline: 1px solid var(--borders-secondary);
15568
15689
  outline-offset: -1px;
15569
15690
  }
15570
15691
  .zen-filters-toolbar {
@@ -17492,6 +17613,10 @@ html:lang(ar) .zen-form-layout-secondary {
17492
17613
  height: 3rem;
17493
17614
  padding: 0.125rem 0.5rem;
17494
17615
  }
17616
+ .zen-main-header--mobile .zen-header__section--left {
17617
+ flex-shrink: 1;
17618
+ min-width: 0;
17619
+ }
17495
17620
  .zen-main-header--limited-title .zen-page-header__page-name {
17496
17621
  max-width: 6.25rem;
17497
17622
  }
@@ -17500,6 +17625,7 @@ html:lang(ar) .zen-form-layout-secondary {
17500
17625
  }
17501
17626
  .zen-main-header.zen-main-header--shrink-title .zen-header__section--left {
17502
17627
  flex-shrink: 1;
17628
+ min-width: 0;
17503
17629
  }
17504
17630
  .zen-main-header.zen-main-header--mobile-title-large .zen-page-header__page-name {
17505
17631
  max-width: 16.25rem;
@@ -19045,8 +19171,13 @@ html:lang(ar) .zen-pill-actionable__block {
19045
19171
  margin-right: 8px;
19046
19172
  }
19047
19173
  .zen-pill-actionable__input {
19174
+ clip: rect(0 0 0 0);
19175
+ clip-path: inset(50%);
19176
+ height: 1px;
19177
+ overflow: hidden;
19048
19178
  position: absolute;
19049
- left: -5000px;
19179
+ white-space: nowrap;
19180
+ width: 1px;
19050
19181
  }
19051
19182
  .zen-pill-actionable__input:hover + .zen-pill-actionable__block--actionable {
19052
19183
  background-color: var(--backgrounds-content-2);
package/dist/index.d.ts CHANGED
@@ -725,7 +725,7 @@ export { isButton } from "./menu/utils/isButton";
725
725
  export { isLink } from "./menu/utils/isLink";
726
726
  export { type IMiniTabElement, MiniTabsSize, type IMiniTabs, MiniTabs } from "./miniTabs/miniTabs";
727
727
  export { type IMobileSheet, MobileSheet } from "./mobileSheet/mobileSheet";
728
- export { type TFocusElement, type IModal, Modal, type IDialogContent, DialogContentNew } from "./modal/modal";
728
+ export { MODAL_SCROLL_LOCK_CLASS, type TFocusElement, type IModal, Modal, type IDialogContent, DialogContentNew } from "./modal/modal";
729
729
  export { getPredefinedFocusableItem } from "./modal/modalHelpers";
730
730
  export { type INotificationProps, Notification } from "./notification/notification";
731
731
  export { type IPageHeader, PageHeaderDisplayName, PageHeader } from "./pageHeader/pageHeader";
@@ -778,7 +778,12 @@ export { type IToggleButtonDefaultRaw, type IToggleButtonRaw, type IToggleButton
778
778
  export { calculateArrowPosition } from "./tooltip/helpers/calculateArrowPosition";
779
779
  export { removeArrowClasses } from "./tooltip/helpers/removeArrowClasses";
780
780
  export { type TooltipSize, type TMobileView, Tooltip } from "./tooltip/tooltip";
781
+ export { type TTrendIndicatorDirection, type TTrendIndicatorTone, type ITrendIndicator } from "./trendIndicator/trendIndicator";
782
+ export { getTrendIndicatorDirection } from "./trendIndicator/trendIndicatorUtils";
781
783
  export { type IAbortablePromiseOptions, type IAbortablePromiseConstructor, AbortablePromise } from "./utils/abortablePromise";
784
+ export { ZenithExperimentalProvider } from "./utils/experimentalFeatures/experimentalContext";
785
+ export { type ExperimentalFeatureId, EXPERIMENTAL_FLAGS } from "./utils/experimentalFeatures/registry";
786
+ export { useExperimentalFeature } from "./utils/experimentalFeatures/useExperimentalFeature";
782
787
  export { HeaderButtonsProvider } from "./utils/headerButtons/headerButtonsProvider";
783
788
  export { getNewFocusableItem, getFirstFocusableItem } from "./utils/keyboardHelpers";
784
789
  export { LanguageProvider } from "./utils/localization/languageProvider";
package/dist/index.js CHANGED
@@ -16,9 +16,9 @@ exports.IconPinLocation2 = exports.IconPinLocation = exports.IconPinFilled = exp
16
16
  exports.IconSettings8 = exports.IconSettings7 = exports.IconSettings6 = exports.IconSettings4 = exports.IconSettings3 = exports.IconSettings2 = exports.IconSettings1 = exports.IconServer3 = exports.IconServer2 = exports.IconServer = exports.IconSend = exports.IconSecuredLines = exports.IconSecured = exports.IconSeatbelt = exports.IconSearchPage = exports.IconSearchLines = exports.IconSearchDocument = exports.IconSearch = exports.IconSdCard = exports.IconRuler = exports.IconRoute = exports.IconRotateRepeat2 = exports.IconRotateRepeat = exports.IconRotateCounterclockwise = exports.IconRotateClockwise = exports.IconResizeSmall = exports.IconResizeBig = exports.IconRepeat2 = exports.IconRepeat = exports.IconRemovePeople = exports.IconRefrigeration = exports.IconRedo2 = exports.IconRedo = exports.IconRecord = exports.IconReceipt = exports.IconRadar = exports.IconQuestion = exports.IconPuzzle = exports.IconPullRequest = exports.IconProcessor = exports.IconPrinter = exports.IconPound = exports.IconPotato = exports.IconPlusSquare = exports.IconPlusLines = exports.IconPlusFile = exports.IconPlusCircle = exports.IconPlus = exports.IconPlay = exports.IconPinLocation3 = void 0;
17
17
  exports.IconUsb = exports.IconUpload = exports.IconUnlocked = exports.IconUndock = exports.IconUndo2 = exports.IconUndo = exports.IconUnderline = exports.IconUmbrella = exports.IconTruck = exports.IconTrendNeutral = exports.IconTrailer = exports.IconToggleSmall = exports.IconToggleLarge = exports.IconThumbsUp = exports.IconThumbsDown = exports.IconThermometer = exports.IconThermograph = exports.IconTextSize = exports.IconTelevision2 = exports.IconTelevision = exports.IconTarget3 = exports.IconTarget2 = exports.IconTarget = exports.IconTachographTimeCard = exports.IconTachograph = exports.IconTable = exports.IconSupport = exports.IconSun = exports.IconStrikeThrough = exports.IconStore = exports.IconStorage = exports.IconStopwatch = exports.IconStarFilled = exports.IconStarAi = exports.IconStar = exports.IconSquare = exports.IconSpeaker = exports.IconSortVertical = exports.IconSortHorizontal = exports.IconSort2Vertical = exports.IconSort2Horizontal = exports.IconSmiley = exports.IconSign = exports.IconSidebar = exports.IconShield4 = exports.IconShield3 = exports.IconShield2 = exports.IconShield = exports.IconShare3 = exports.IconShare = void 0;
18
18
  exports.ListItem = exports.List = exports.ItemData = exports.ItemCompact = exports.LineChartMini = exports.getDefaultDatasetStyle = exports.htmlLegendPlugin = exports.LEGEND_PLUGIN_ID = exports.LineChart = exports.useLayoutSize = exports.LayoutFullScreenProvider = exports.useLayoutFullScreen = exports.LayoutFullScreenElementProvider = exports.useLayoutFullScreenElement = exports.Layout = exports.ImageTapToUpload = exports.ImageNothingFound = exports.ImageNoMatchingAssets = exports.ImageLooking = exports.ImageCloudUpload = exports.ImageAdjustFilter = exports.IconZoom2 = exports.IconZoom = exports.IconZone = exports.IconYen = exports.IconWrite = exports.IconWrench = exports.IconWorld = exports.IconWorkday = exports.IconWifi2 = exports.IconWifi = exports.IconWhisper = exports.IconWebcam = exports.IconWatch2 = exports.IconWatch = exports.IconWarning = exports.IconWallet1 = exports.IconWallet = exports.IconVolumeOn = exports.IconVolumeOff = exports.IconVolumeMinimum = exports.IconVolumeHalf = exports.IconVolumeFull = exports.IconVolumeDown = exports.IconVoice = exports.IconVisitPage = exports.IconVideoReplay = exports.IconVideo2 = exports.IconVideo = exports.IconUsbHub = void 0;
19
- exports.Summaries = exports.Stepper = exports.SortControl = exports.SortDirections = exports.Skeleton = exports.LazyContent = exports.SidePanel = exports.CUSTOM_POPUP_COMPONENT_CLASSNAME = exports.SidePanelCloseReason = exports.isChildPopup = exports.SelectField = exports.Select = exports.SearchInput = exports.Range = exports.RadioGroup = exports.Radio = exports.ProgressBar = exports.ProgreesBarSize = exports.ProgressBarType = exports.PrimaryIcon = exports.Popup = exports.PillExpandable = exports.Pill = exports.PaginationType = exports.Pagination = exports.PageLayout = exports.PageContentLayout = exports.PageHeaderMenu = exports.PageHeaderMenuDisplayName = exports.PageHeaderButton = exports.PageHeaderButtonDisplayName = exports.PageHeader = exports.PageHeaderDisplayName = exports.Notification = exports.getPredefinedFocusableItem = exports.DialogContentNew = exports.Modal = exports.MobileSheet = exports.MiniTabs = exports.MiniTabsSize = exports.isLink = exports.isButton = exports.findPrevFocusable = exports.findNextFocusable = exports.findLastFocusable = exports.findFirstFocusable = exports.Menu = exports.ControlledMenu = exports.isDragNotClick = exports.changeOrder = void 0;
20
- exports.useDrive = exports.ThemeProvider = exports.ThemeDrive = exports.ThemeDark = exports.useLanguage = exports.useDirection = exports.injectString = exports.dictionaries = exports.LanguageProvider = exports.getFirstFocusableItem = exports.getNewFocusableItem = exports.HeaderButtonsProvider = exports.AbortablePromise = exports.Tooltip = exports.removeArrowClasses = exports.calculateArrowPosition = exports.ToggleButtonRaw = exports.ToggleButton = exports.Toast = exports.useToast = exports.TimePicker = exports.TextareaRaw = exports.Textarea = exports.TextInputRaw = exports.TextInput = exports.TextIconButton = exports.ButtonIconPosition = exports.Tabs = exports.TabsDisplayName = exports.ActionLinkColumn = exports.CheckboxColumn = exports.MainColumn = exports.ActionsColumn = exports.getSortableValue = exports.ColumnSortDirection = exports.getEmptySelection = exports.Table = exports.useNestedRows = exports.NestedData = exports.TabBarContent = exports.TabBar = exports.SummaryTileBarDisplayName = exports.SummaryTileBar = exports.getTypeClassName = exports.SummaryTileTrigger = exports.SummaryTile = exports.SummaryTileDisplayName = exports.SummaryTileSize = exports.SummaryTileType = exports.Summary = void 0;
21
- exports.Waiting = exports.UserFormatProvider = void 0;
19
+ exports.Stepper = exports.SortControl = exports.SortDirections = exports.Skeleton = exports.LazyContent = exports.SidePanel = exports.CUSTOM_POPUP_COMPONENT_CLASSNAME = exports.SidePanelCloseReason = exports.isChildPopup = exports.SelectField = exports.Select = exports.SearchInput = exports.Range = exports.RadioGroup = exports.Radio = exports.ProgressBar = exports.ProgreesBarSize = exports.ProgressBarType = exports.PrimaryIcon = exports.Popup = exports.PillExpandable = exports.Pill = exports.PaginationType = exports.Pagination = exports.PageLayout = exports.PageContentLayout = exports.PageHeaderMenu = exports.PageHeaderMenuDisplayName = exports.PageHeaderButton = exports.PageHeaderButtonDisplayName = exports.PageHeader = exports.PageHeaderDisplayName = exports.Notification = exports.getPredefinedFocusableItem = exports.DialogContentNew = exports.Modal = exports.MODAL_SCROLL_LOCK_CLASS = exports.MobileSheet = exports.MiniTabs = exports.MiniTabsSize = exports.isLink = exports.isButton = exports.findPrevFocusable = exports.findNextFocusable = exports.findLastFocusable = exports.findFirstFocusable = exports.Menu = exports.ControlledMenu = exports.isDragNotClick = exports.changeOrder = void 0;
20
+ exports.useDirection = exports.injectString = exports.dictionaries = exports.LanguageProvider = exports.getFirstFocusableItem = exports.getNewFocusableItem = exports.HeaderButtonsProvider = exports.useExperimentalFeature = exports.EXPERIMENTAL_FLAGS = exports.ZenithExperimentalProvider = exports.AbortablePromise = exports.getTrendIndicatorDirection = exports.Tooltip = exports.removeArrowClasses = exports.calculateArrowPosition = exports.ToggleButtonRaw = exports.ToggleButton = exports.Toast = exports.useToast = exports.TimePicker = exports.TextareaRaw = exports.Textarea = exports.TextInputRaw = exports.TextInput = exports.TextIconButton = exports.ButtonIconPosition = exports.Tabs = exports.TabsDisplayName = exports.ActionLinkColumn = exports.CheckboxColumn = exports.MainColumn = exports.ActionsColumn = exports.getSortableValue = exports.ColumnSortDirection = exports.getEmptySelection = exports.Table = exports.useNestedRows = exports.NestedData = exports.TabBarContent = exports.TabBar = exports.SummaryTileBarDisplayName = exports.SummaryTileBar = exports.getTypeClassName = exports.SummaryTileTrigger = exports.SummaryTile = exports.SummaryTileDisplayName = exports.SummaryTileSize = exports.SummaryTileType = exports.Summary = exports.Summaries = void 0;
21
+ exports.Waiting = exports.UserFormatProvider = exports.useDrive = exports.ThemeProvider = exports.ThemeDrive = exports.ThemeDark = exports.useLanguage = void 0;
22
22
  /* eslint-disable max-len */
23
23
  var absolute_1 = require("./absolute/absolute");
24
24
  Object.defineProperty(exports, "Absolute", { enumerable: true, get: function () { return absolute_1.Absolute; } });
@@ -1546,6 +1546,7 @@ Object.defineProperty(exports, "MiniTabs", { enumerable: true, get: function ()
1546
1546
  var mobileSheet_1 = require("./mobileSheet/mobileSheet");
1547
1547
  Object.defineProperty(exports, "MobileSheet", { enumerable: true, get: function () { return mobileSheet_1.MobileSheet; } });
1548
1548
  var modal_1 = require("./modal/modal");
1549
+ Object.defineProperty(exports, "MODAL_SCROLL_LOCK_CLASS", { enumerable: true, get: function () { return modal_1.MODAL_SCROLL_LOCK_CLASS; } });
1549
1550
  Object.defineProperty(exports, "Modal", { enumerable: true, get: function () { return modal_1.Modal; } });
1550
1551
  Object.defineProperty(exports, "DialogContentNew", { enumerable: true, get: function () { return modal_1.DialogContentNew; } });
1551
1552
  var modalHelpers_1 = require("./modal/modalHelpers");
@@ -1670,8 +1671,16 @@ var removeArrowClasses_1 = require("./tooltip/helpers/removeArrowClasses");
1670
1671
  Object.defineProperty(exports, "removeArrowClasses", { enumerable: true, get: function () { return removeArrowClasses_1.removeArrowClasses; } });
1671
1672
  var tooltip_1 = require("./tooltip/tooltip");
1672
1673
  Object.defineProperty(exports, "Tooltip", { enumerable: true, get: function () { return tooltip_1.Tooltip; } });
1674
+ var trendIndicatorUtils_1 = require("./trendIndicator/trendIndicatorUtils");
1675
+ Object.defineProperty(exports, "getTrendIndicatorDirection", { enumerable: true, get: function () { return trendIndicatorUtils_1.getTrendIndicatorDirection; } });
1673
1676
  var abortablePromise_1 = require("./utils/abortablePromise");
1674
1677
  Object.defineProperty(exports, "AbortablePromise", { enumerable: true, get: function () { return abortablePromise_1.AbortablePromise; } });
1678
+ var experimentalContext_1 = require("./utils/experimentalFeatures/experimentalContext");
1679
+ Object.defineProperty(exports, "ZenithExperimentalProvider", { enumerable: true, get: function () { return experimentalContext_1.ZenithExperimentalProvider; } });
1680
+ var registry_1 = require("./utils/experimentalFeatures/registry");
1681
+ Object.defineProperty(exports, "EXPERIMENTAL_FLAGS", { enumerable: true, get: function () { return registry_1.EXPERIMENTAL_FLAGS; } });
1682
+ var useExperimentalFeature_1 = require("./utils/experimentalFeatures/useExperimentalFeature");
1683
+ Object.defineProperty(exports, "useExperimentalFeature", { enumerable: true, get: function () { return useExperimentalFeature_1.useExperimentalFeature; } });
1675
1684
  var headerButtonsProvider_1 = require("./utils/headerButtons/headerButtonsProvider");
1676
1685
  Object.defineProperty(exports, "HeaderButtonsProvider", { enumerable: true, get: function () { return headerButtonsProvider_1.HeaderButtonsProvider; } });
1677
1686
  var keyboardHelpers_1 = require("./utils/keyboardHelpers");
@@ -4,6 +4,11 @@ import { IZenComponentProps } from "../commonHelpers/zenComponent";
4
4
  import { IIcon } from "../icons/icon";
5
5
  import { TButtonIconPosition } from "../textIconButton/textIconButton";
6
6
  import { TSvgIconSize } from "../svgIcon/svgIconSize";
7
+ /**
8
+ * The CSS class applied to `document.body` while a Modal is open to prevent page scrolling.
9
+ * Exported so consumers can reference it without coupling to internal implementation details.
10
+ */
11
+ export declare const MODAL_SCROLL_LOCK_CLASS = "zen-modal-content--hidden-overflow";
7
12
  interface IButtonIconProps {
8
13
  icon?: React.FC<IIcon>;
9
14
  iconPosition?: TButtonIconPosition;
@@ -38,6 +43,49 @@ export interface IModal {
38
43
  className?: string;
39
44
  modalContainerClassName?: string;
40
45
  focus?: TFocusElement;
46
+ /**
47
+ * Called once the body scroll-lock has been synchronously released after the modal closes.
48
+ * Use this to safely sequence scroll operations that depend on the modal being fully closed.
49
+ *
50
+ * **Triggers:** the callback fires in two scenarios:
51
+ * - `isOpen` transitions from `true` to `false` (normal close)
52
+ * - The component unmounts while `isOpen` is still `true` (e.g. conditional rendering with
53
+ * `{condition && <Modal isOpen={true} ... />}` where `condition` flips to `false`)
54
+ *
55
+ * It is **not** called when the modal mounts already closed, or when `isOpen` remains `false`
56
+ * across re-renders.
57
+ *
58
+ * **Layout-phase timing:** this callback fires inside a `useLayoutEffect` cleanup, which runs
59
+ * synchronously before the browser paints. This makes it safe for DOM reads and imperative
60
+ * scroll operations. However, calling `setState` inside this callback will trigger an
61
+ * additional synchronous re-render before the next paint — prefer keeping the callback
62
+ * side-effect-free or deferring state updates with `setTimeout`/`queueMicrotask` if needed.
63
+ *
64
+ * **React Strict Mode (development only):** React 18 Strict Mode intentionally
65
+ * double-invokes effects on mount (setup → cleanup → setup) to surface side-effect bugs.
66
+ * If `isOpen` is `true` on initial render, the cleanup from the first (discarded) mount
67
+ * fires with `wasOpen.current = true`, which triggers this callback once at mount even
68
+ * though the modal has not closed. This is a dev-mode artefact and does not occur in
69
+ * production builds.
70
+ *
71
+ * @example
72
+ * ```tsx
73
+ * // Safe: imperative scroll (no state update)
74
+ * <Modal
75
+ * isOpen={isOpen}
76
+ * onScrollLockReleased={() => window.scrollTo({ top: newSectionOffset, behavior: "smooth" })}
77
+ * ...
78
+ * />
79
+ *
80
+ * // Use caution: setState inside the callback causes a synchronous re-render before paint
81
+ * <Modal
82
+ * isOpen={isOpen}
83
+ * onScrollLockReleased={() => setScrollTarget(newSectionOffset)}
84
+ * ...
85
+ * />
86
+ * ```
87
+ */
88
+ onScrollLockReleased?: () => void;
41
89
  }
42
90
  export declare const Modal: FC<IModal> & {
43
91
  Content: FC<IDialogContent>;
@@ -47,7 +47,7 @@ var __importStar = this && this.__importStar || function () {
47
47
  Object.defineProperty(exports, "__esModule", {
48
48
  value: true
49
49
  });
50
- exports.DialogContentNew = exports.Modal = void 0;
50
+ exports.DialogContentNew = exports.Modal = exports.MODAL_SCROLL_LOCK_CLASS = void 0;
51
51
  const jsx_runtime_1 = require("react/jsx-runtime");
52
52
  /* eslint-disable @typescript-eslint/naming-convention */
53
53
  injectString("cs", "Close", "Zav\u0159\xEDt");
@@ -104,6 +104,11 @@ const textIconButton_1 = require("../textIconButton/textIconButton");
104
104
  const useClientReady_1 = require("../commonHelpers/hooks/useClientReady");
105
105
  const zen_1 = require("../utils/zen");
106
106
  const react_dom_1 = require("react-dom");
107
+ /**
108
+ * The CSS class applied to `document.body` while a Modal is open to prevent page scrolling.
109
+ * Exported so consumers can reference it without coupling to internal implementation details.
110
+ */
111
+ exports.MODAL_SCROLL_LOCK_CLASS = "zen-modal-content--hidden-overflow";
107
112
  const Modal = ({
108
113
  isOpen,
109
114
  children,
@@ -114,7 +119,8 @@ const Modal = ({
114
119
  type,
115
120
  className,
116
121
  focus,
117
- modalContainerClassName
122
+ modalContainerClassName,
123
+ onScrollLockReleased
118
124
  }) => {
119
125
  var _a, _b, _c;
120
126
  const lastActiveOutsideElement = (0, react_1.useRef)((_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.activeElement);
@@ -123,6 +129,14 @@ const Modal = ({
123
129
  dark
124
130
  } = (0, react_1.useContext)(themeContext_1.themeContext);
125
131
  const isClientReady = (0, useClientReady_1.useClientReady)();
132
+ // Tracks whether the modal was open on the previous render so we can detect open→closed transitions.
133
+ const wasOpen = (0, react_1.useRef)(false);
134
+ // Keep the latest callback in a ref so it never needs to enter the useLayoutEffect deps array.
135
+ // Assigning directly in the render body (rather than via a sync effect) guarantees the ref is
136
+ // always current before any effects or cleanups run in the same commit — eliminating the stale
137
+ // callback edge case that occurred when isOpen and onScrollLockReleased changed simultaneously.
138
+ const onScrollLockReleasedRef = (0, react_1.useRef)(onScrollLockReleased);
139
+ onScrollLockReleasedRef.current = onScrollLockReleased;
126
140
  const onOutSideClick = (0, react_1.useCallback)(() => {
127
141
  if (!isClientReady) {
128
142
  return;
@@ -141,19 +155,35 @@ const Modal = ({
141
155
  (0, dialogHelpers_1.isFocusable)(copyActive) && copyActive.focus();
142
156
  };
143
157
  }, [isClientReady]);
144
- (0, react_1.useEffect)(() => {
158
+ // useLayoutEffect runs synchronously after DOM mutations, before the browser paints.
159
+ // This guarantees the scroll-lock class is removed (and onScrollLockReleased fires)
160
+ // before the browser repaints — eliminating the timing gap that existed with useEffect.
161
+ // onScrollLockReleased is intentionally excluded from deps: it is read via ref so that
162
+ // inline arrow functions passed by consumers do not cause redundant DOM mutations on
163
+ // every parent re-render while the modal is open.
164
+ (0, react_1.useLayoutEffect)(() => {
145
165
  var _a, _b;
146
166
  if (!isClientReady) {
147
167
  return undefined;
148
168
  }
149
- (_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.body.classList.remove("zen-modal-content--hidden-overflow");
169
+ (_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.body.classList.remove(exports.MODAL_SCROLL_LOCK_CLASS);
150
170
  if (isOpen) {
151
- (_b = zen_1.zen.document) === null || _b === void 0 ? void 0 : _b.body.classList.add("zen-modal-content--hidden-overflow");
171
+ wasOpen.current = true;
172
+ (_b = zen_1.zen.document) === null || _b === void 0 ? void 0 : _b.body.classList.add(exports.MODAL_SCROLL_LOCK_CLASS);
152
173
  }
153
174
  return () => {
154
- var _a;
155
- (_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.body.classList.remove("zen-modal-content--hidden-overflow");
175
+ var _a, _b;
176
+ (_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.body.classList.remove(exports.MODAL_SCROLL_LOCK_CLASS);
177
+ // Fire the callback in cleanup so it is triggered in both cases:
178
+ // 1. isOpen prop transitions true → false
179
+ // 2. component unmounts while isOpen is still true
180
+ // wasOpen guards against spurious calls (e.g. closing an already-closed modal).
181
+ if (wasOpen.current) {
182
+ wasOpen.current = false;
183
+ (_b = onScrollLockReleasedRef.current) === null || _b === void 0 ? void 0 : _b.call(onScrollLockReleasedRef);
184
+ }
156
185
  };
186
+ // eslint-disable-next-line react-hooks/exhaustive-deps
157
187
  }, [isClientReady, isOpen]);
158
188
  (0, react_1.useEffect)(() => {
159
189
  var _a, _b;
@@ -28,7 +28,7 @@ export declare const NavHeader: FC<INavHeader> & {
28
28
  * @deprecated Use NavItem instead. Will be removed in future releases.
29
29
  */
30
30
  Action: {
31
- (props: import("../navItem/navItem").ILinkNavItem | import("../navItem/navItem").IButtonNavItem): import("react/jsx-runtime").JSX.Element;
31
+ (props: import("../navItem/navItem").ILinkNavItem | import("../navItem/navItem").TButtonNavItem): import("react/jsx-runtime").JSX.Element;
32
32
  displayName: string;
33
33
  };
34
34
  Search: {
@@ -136,7 +136,7 @@ const NavHeaderSearch = ({
136
136
  onClick: () => onSearchToggle === null || onSearchToggle === void 0 ? void 0 : onSearchToggle(true),
137
137
  tooltipAlignment: collapsed ? "end" : "bottom"
138
138
  }) : null, searchOpen || isMobile ? (0, jsx_runtime_1.jsx)(searchInput_1.SearchInput, {
139
- autoFocus: true,
139
+ autoFocus: searchOpen,
140
140
  ariaLabel: translate("Search"),
141
141
  value: searchTerm,
142
142
  placeholder: translate("Search"),
@@ -26,11 +26,24 @@ interface INavItemCommon extends IZenComponentProps {
26
26
  export interface ILinkNavItem extends INavItemCommon {
27
27
  link: string;
28
28
  }
29
- export interface IButtonNavItem extends INavItemCommon {
29
+ interface IButtonNavItemBase extends INavItemCommon {
30
30
  onClick?: () => void;
31
31
  menuAlignment?: TAlignment;
32
32
  onDropdownStateChange?: (isOpen: boolean) => void;
33
33
  }
34
+ export type TNavItemPopupType = "dialog" | "menu" | "listbox" | "tree" | "grid";
35
+ export interface IPopupButtonNavItem extends IButtonNavItemBase {
36
+ popupId: string;
37
+ isPopupOpen: boolean;
38
+ popupType?: TNavItemPopupType;
39
+ children?: never;
40
+ }
41
+ interface IPlainButtonNavItem extends IButtonNavItemBase {
42
+ popupId?: never;
43
+ isPopupOpen?: never;
44
+ popupType?: never;
45
+ }
46
+ export type TButtonNavItem = IPlainButtonNavItem | IPopupButtonNavItem;
34
47
  interface INavItemContext {
35
48
  parentLevel?: number;
36
49
  closeParentMenu?: () => void;
@@ -40,7 +53,7 @@ export declare const NavItemContext: import("react").Context<INavItemContext>;
40
53
  * @beta This component is not fully ready yet and may change in future releases.
41
54
  */
42
55
  export declare const NavItem: {
43
- (props: ILinkNavItem | IButtonNavItem): import("react/jsx-runtime").JSX.Element;
56
+ (props: ILinkNavItem | TButtonNavItem): import("react/jsx-runtime").JSX.Element;
44
57
  displayName: string;
45
58
  };
46
59
  export {};