@esri/calcite-components 5.2.0-next.6 → 5.2.0-next.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/dist/cdn/{Z57BICST.js → 22N7ARV7.js} +1 -1
  2. package/dist/cdn/255CJNBQ.js +2 -0
  3. package/dist/cdn/{2MVXV2MI.js → 2B5SK2B4.js} +1 -1
  4. package/dist/cdn/{KCNDBMLL.js → 2DVSDS5W.js} +1 -1
  5. package/dist/cdn/{AQJNAUQZ.js → 2W5AIJ3P.js} +1 -1
  6. package/dist/cdn/{7WN6WR2B.js → 2X6QZRGI.js} +1 -1
  7. package/dist/cdn/{L22NWLBO.js → 2ZLARVHZ.js} +1 -1
  8. package/dist/cdn/{M2KR7ZH5.js → 37C2BTJH.js} +1 -1
  9. package/dist/cdn/{GQHRGQXT.js → 3DZCTGTX.js} +1 -1
  10. package/dist/cdn/{WBIPNNGL.js → 3FM74CVY.js} +1 -1
  11. package/dist/cdn/{AGH5I4NC.js → 3IMK322V.js} +1 -1
  12. package/dist/cdn/{LII6G3V3.js → 3ND6JJU2.js} +1 -1
  13. package/dist/cdn/{Y5DQ7II6.js → 45ZL6S2L.js} +1 -1
  14. package/dist/cdn/{Y4OMJTVI.js → 4HQGPAC7.js} +1 -1
  15. package/dist/cdn/{SUMMJWW7.js → 4RYFAF65.js} +1 -1
  16. package/dist/cdn/{JJQGOFEM.js → 4SXYANKI.js} +1 -1
  17. package/dist/cdn/{ESHAWAWL.js → 4ZQOFYGA.js} +1 -1
  18. package/dist/cdn/{4STE75YI.js → 5BBXVTVC.js} +1 -1
  19. package/dist/cdn/{Z2RDFJ3O.js → 5HP5FZAB.js} +1 -1
  20. package/dist/cdn/{LZMQVYXJ.js → 5L75WHPS.js} +1 -1
  21. package/dist/cdn/{L4DOJVLT.js → 5W44MDZE.js} +1 -1
  22. package/dist/cdn/{FF3BNERI.js → 67HJME4D.js} +1 -1
  23. package/dist/cdn/{VTB66B24.js → 6A6DR3VH.js} +1 -1
  24. package/dist/cdn/{VV7SRS22.js → 6C54IW5E.js} +1 -1
  25. package/dist/cdn/{RFXCFK6K.js → 6MJP7OIJ.js} +1 -1
  26. package/dist/cdn/{J5H2LW3F.js → 6TCERT23.js} +1 -1
  27. package/dist/cdn/{EKQRORSO.js → 6VGI37NE.js} +1 -1
  28. package/dist/cdn/{HI4AC5NT.js → 744TBMM3.js} +1 -1
  29. package/dist/cdn/{RUVRJVVT.js → 7BIEHNBN.js} +1 -1
  30. package/dist/cdn/{PZXDAKVC.js → 7HMML2DR.js} +1 -1
  31. package/dist/cdn/{G3Y3LVCH.js → 7KVOA3RG.js} +1 -1
  32. package/dist/cdn/{Q6HQOCPI.js → 7QSFRDV5.js} +1 -1
  33. package/dist/cdn/{FU52LD3F.js → AE4FA7FY.js} +1 -1
  34. package/dist/cdn/{4FFUO6AL.js → AEUGG6UI.js} +1 -1
  35. package/dist/cdn/{ZYLB2RT3.js → AFLT7NPW.js} +1 -1
  36. package/dist/cdn/{27TMS7TL.js → AQOHIR7I.js} +1 -1
  37. package/dist/cdn/{ZW25BB34.js → B5M6XZPQ.js} +1 -1
  38. package/dist/cdn/{NKMMLWMY.js → BDRBFTUJ.js} +1 -1
  39. package/dist/cdn/{55ECBMKY.js → BE7SWPCI.js} +1 -1
  40. package/dist/cdn/{SA35OSIJ.js → BM7PKEQF.js} +1 -1
  41. package/dist/cdn/{MOSQZFYT.js → BZR7SCVQ.js} +1 -1
  42. package/dist/cdn/{VCQ5M2XF.js → C3EMHXIX.js} +1 -1
  43. package/dist/cdn/{ZMJFSBIG.js → C5A7GGD4.js} +1 -1
  44. package/dist/cdn/{DXYF2XAM.js → CA6ESPGD.js} +1 -1
  45. package/dist/cdn/{CA2SBV2Y.js → CJMUF6Z7.js} +1 -1
  46. package/dist/cdn/D3VMRWYN.js +2 -0
  47. package/dist/cdn/{524GQTNG.js → D4HPNC3L.js} +1 -1
  48. package/dist/cdn/{BJOJINNV.js → DHCG4KMO.js} +1 -1
  49. package/dist/cdn/{H6QON2TD.js → DS5VHI4Z.js} +1 -1
  50. package/dist/cdn/{NVF4K6HP.js → DU34ZRAK.js} +1 -1
  51. package/dist/cdn/{CKF3HEXO.js → EEHC75BT.js} +1 -1
  52. package/dist/cdn/{PQ7DCUPL.js → EHGKLR2I.js} +1 -1
  53. package/dist/cdn/{QBOTNUZA.js → EIG5UNV3.js} +1 -1
  54. package/dist/cdn/{25HEUF62.js → EM2QRJCP.js} +1 -1
  55. package/dist/cdn/{KWIJFLPJ.js → ET5QQ6ZE.js} +1 -1
  56. package/dist/cdn/{2VQ4SQ6E.js → FHFQFLLV.js} +1 -1
  57. package/dist/cdn/{MEMDH5M4.js → FJWV33EJ.js} +1 -1
  58. package/dist/cdn/{HELW7C5O.js → FL5AI52A.js} +1 -1
  59. package/dist/cdn/{TMENZ2VZ.js → FQGP2TF4.js} +1 -1
  60. package/dist/cdn/{GYJEWH7E.js → FQU67QYY.js} +1 -1
  61. package/dist/cdn/{WYO3R6BR.js → GGJZTKGX.js} +1 -1
  62. package/dist/cdn/{CL5AZEAL.js → GMEB4FUQ.js} +1 -1
  63. package/dist/cdn/{AJYPMLTJ.js → GQSSPVYH.js} +1 -1
  64. package/dist/cdn/{ISVN563X.js → GZNLRM76.js} +1 -1
  65. package/dist/cdn/{HYS3KXOM.js → GZTMMGCJ.js} +1 -1
  66. package/dist/cdn/{VYBYSRSC.js → H7UZS446.js} +1 -1
  67. package/dist/cdn/{NTJQBE2P.js → HBLG43FI.js} +1 -1
  68. package/dist/cdn/{XGSEBUKD.js → HCQ73WZV.js} +1 -1
  69. package/dist/cdn/{3KPPK6JG.js → HEIJ72GT.js} +1 -1
  70. package/dist/cdn/{3VB4KSXM.js → HMXCTTUK.js} +1 -1
  71. package/dist/cdn/{5BGGNWJQ.js → HXT7NOOV.js} +1 -1
  72. package/dist/cdn/{5OJ3Q4SI.js → IHPU7EWA.js} +1 -1
  73. package/dist/cdn/{DAE6OWX6.js → IJAMTOKN.js} +1 -1
  74. package/dist/cdn/{QXDIQQGO.js → J7FC6ZPY.js} +1 -1
  75. package/dist/cdn/{MKFZEFQ6.js → JB4DSSHG.js} +1 -1
  76. package/dist/cdn/{TD3YG3I3.js → JCW6IR2I.js} +1 -1
  77. package/dist/cdn/{HRLK2RSF.js → JI2XHUUM.js} +1 -1
  78. package/dist/cdn/{EDSYBZIF.js → JPRBZLNY.js} +1 -1
  79. package/dist/cdn/{ET7FYLD3.js → JQA4RU76.js} +1 -1
  80. package/dist/cdn/{5TUWUQHN.js → KCL3KOWK.js} +1 -1
  81. package/dist/cdn/{JPSCTBEO.js → KV4UMXMD.js} +1 -1
  82. package/dist/cdn/{STVS4SFC.js → M5GCKYUY.js} +1 -1
  83. package/dist/cdn/{UGLRJ7LC.js → MDMDAT7S.js} +1 -1
  84. package/dist/cdn/{KHVMN3I6.js → MEPDW4WV.js} +1 -1
  85. package/dist/cdn/{QB2FASAQ.js → MLDTAC4V.js} +1 -1
  86. package/dist/cdn/{WHJTD6F6.js → MO5PWDHH.js} +1 -1
  87. package/dist/cdn/{Z3MFTUAY.js → MWHL3FGX.js} +1 -1
  88. package/dist/cdn/{O63QYVPR.js → N2LGKOPB.js} +1 -1
  89. package/dist/cdn/{Y47AW44L.js → N3XTOHD4.js} +1 -1
  90. package/dist/cdn/{DQBHDK7Y.js → NCAFX2IU.js} +1 -1
  91. package/dist/cdn/{RWITZVQC.js → NEBN6Q6V.js} +1 -1
  92. package/dist/cdn/{RWYSLJFS.js → NFDSCUC7.js} +1 -1
  93. package/dist/cdn/{XJAWMEAX.js → NFHPGWE3.js} +1 -1
  94. package/dist/cdn/{IMZBK4NI.js → NMBCJCCO.js} +1 -1
  95. package/dist/cdn/{XVHDY6QN.js → NRYSWYNK.js} +1 -1
  96. package/dist/cdn/{QM74WXQL.js → NU72X3HS.js} +1 -1
  97. package/dist/cdn/{H4DY4JG2.js → NXUFQ4YS.js} +1 -1
  98. package/dist/cdn/{OQ4ME7QP.js → O2QQXYDW.js} +1 -1
  99. package/dist/cdn/{6UNW5QUY.js → OFDHYKQN.js} +1 -1
  100. package/dist/cdn/{LF3SYGBF.js → OINOBLBC.js} +1 -1
  101. package/dist/cdn/{6JPWON4E.js → OR55DZMS.js} +1 -1
  102. package/dist/cdn/{BRRREDR5.js → ORKUIIJK.js} +1 -1
  103. package/dist/cdn/{QSYX3KO4.js → PQK6ETUC.js} +1 -1
  104. package/dist/cdn/{N3D6FMEH.js → PQLUXN7R.js} +1 -1
  105. package/dist/cdn/{U34FLFGP.js → Q5CRHYT4.js} +1 -1
  106. package/dist/cdn/{IQFKCBYR.js → Q67TFS2A.js} +1 -1
  107. package/dist/cdn/{EOLQCEAO.js → QENJY6C7.js} +1 -1
  108. package/dist/cdn/{DIIBT6ES.js → QJF5YGPY.js} +1 -1
  109. package/dist/cdn/{2HYBPCP5.js → QLNBJ3D2.js} +1 -1
  110. package/dist/cdn/{T6FWGIF5.js → R35E6X4J.js} +1 -1
  111. package/dist/cdn/{ZO734Y5U.js → RBSWNTNU.js} +1 -1
  112. package/dist/cdn/{7KYHXTZ7.js → RDBTAJCH.js} +1 -1
  113. package/dist/cdn/{3IIMBPGI.js → RYR7RCAB.js} +1 -1
  114. package/dist/cdn/{LB3LM7KW.js → S5YU36AW.js} +1 -1
  115. package/dist/cdn/{75TN3ELK.js → SBWEXBSU.js} +1 -1
  116. package/dist/cdn/{SOLIHAFU.js → SEHJ4RKZ.js} +1 -1
  117. package/dist/cdn/{FEIOKH52.js → SRGRHGJ5.js} +1 -1
  118. package/dist/cdn/{OFWHQQ3T.js → SU7BYFW3.js} +1 -1
  119. package/dist/cdn/{KZ3ACECQ.js → SVJV6P4P.js} +1 -1
  120. package/dist/cdn/{SRKLCLO7.js → TOJCGSWL.js} +1 -1
  121. package/dist/cdn/{6SWGOABM.js → TSXOSLFT.js} +1 -1
  122. package/dist/cdn/{LFL2NOMX.js → U5NEBHS5.js} +1 -1
  123. package/dist/cdn/{6XR57LJ6.js → UES5LGVM.js} +1 -1
  124. package/dist/cdn/{AXRVR7RO.js → UJRRKIO7.js} +1 -1
  125. package/dist/cdn/{7QATBQUC.js → UL7L5FJO.js} +1 -1
  126. package/dist/cdn/{GH2UFRFZ.js → UOHGU4YY.js} +1 -1
  127. package/dist/cdn/{6QSTWKNM.js → V6FHFWKX.js} +1 -1
  128. package/dist/cdn/{KHGZVW5S.js → VPVCIXE2.js} +1 -1
  129. package/dist/cdn/{MS7U4EKG.js → WEXOUBDS.js} +1 -1
  130. package/dist/cdn/{LQJYSCJD.js → WF6BMZT7.js} +1 -1
  131. package/dist/cdn/{C2SFDYFY.js → WSZFROTG.js} +1 -1
  132. package/dist/cdn/{KNOX6XCS.js → WYAVJAPT.js} +1 -1
  133. package/dist/cdn/{LMPBTORD.js → WYOJIAFW.js} +1 -1
  134. package/dist/cdn/{G2XUNH4V.js → X37OGDUE.js} +1 -1
  135. package/dist/cdn/{H5PHSNTL.js → XG27KSRC.js} +1 -1
  136. package/dist/cdn/{JTUQOIII.js → XJ36MZLC.js} +1 -1
  137. package/dist/cdn/{RZKOBNPA.js → XZJNARMG.js} +1 -1
  138. package/dist/cdn/{2D5TGEGM.js → YXRKYXM3.js} +1 -1
  139. package/dist/cdn/{VCM2ZHPT.js → YZHTEJRH.js} +1 -1
  140. package/dist/cdn/{JE7COWZ4.js → Z3UI7HPY.js} +1 -1
  141. package/dist/cdn/{BDIWM5DD.js → ZEDBMSXG.js} +1 -1
  142. package/dist/cdn/{PKFY2P43.js → ZHL36WFZ.js} +1 -1
  143. package/dist/cdn/{L77XFD22.js → ZMVMH3BK.js} +1 -1
  144. package/dist/cdn/{5SJ7DUTY.js → ZPQZYGS3.js} +1 -1
  145. package/dist/cdn/index.js +1 -1
  146. package/dist/chunks/runtime.js +4 -4
  147. package/dist/components/calcite-tab-nav/customElement.js +63 -25
  148. package/dist/components/calcite-tab-title/customElement.js +4 -0
  149. package/dist/components/calcite-tabs/customElement.d.ts +6 -0
  150. package/dist/components/calcite-tabs/customElement.js +13 -7
  151. package/dist/docs/api.json +1 -1
  152. package/dist/docs/docs.json +1 -1
  153. package/dist/docs/vscode.html-custom-data.json +1 -1
  154. package/dist/docs/web-types.json +1 -1
  155. package/dist/loader.js +2 -2
  156. package/dist/types/lumina.d.ts +1 -1
  157. package/dist/types/preact.d.ts +1 -1
  158. package/dist/types/react.d.ts +1 -1
  159. package/dist/types/stencil.d.ts +1 -1
  160. package/package.json +2 -2
  161. package/dist/cdn/6SJW5IBJ.js +0 -2
  162. package/dist/cdn/P2BT5ISA.js +0 -2
@@ -33,12 +33,13 @@ class TabNav extends LitElement {
33
33
  this.resizeObserver = createObserver("resize", () => {
34
34
  this.updateScrollingState();
35
35
  });
36
- this.makeFirstVisibleTabClosable = false;
37
36
  this.messages = useT9n();
38
37
  this.hasOverflowingEndTabTitle = false;
39
38
  this.hasOverflowingStartTabTitle = false;
39
+ this.hasVisibleTabTitles = true;
40
40
  this.bordered = false;
41
41
  this.layout = "inline";
42
+ this.lastTabClosable = false;
42
43
  this.position = "bottom";
43
44
  this.scale = "m";
44
45
  this.selectedTitle = null;
@@ -49,13 +50,14 @@ class TabNav extends LitElement {
49
50
  this.listen("calciteInternalTabsFocusNext", this.focusNextTabHandler);
50
51
  this.listen("calciteInternalTabsFocusFirst", this.focusFirstTabHandler);
51
52
  this.listen("calciteInternalTabsFocusLast", this.focusLastTabHandler);
53
+ this.listen("calciteInternalTabTitleCloseChange", this.syncVisibleTabTitlesState);
52
54
  this.listen("calciteInternalTabTitleRegister", this.updateTabTitles);
53
55
  this.listen("calciteInternalTabsActivate", this.internalActivateTabHandler);
54
56
  this.listen("calciteInternalTabsClose", this.internalCloseTabHandler);
55
57
  this.listenOn(document.body, "calciteInternalTabChange", this.globalInternalTabChangeHandler);
56
58
  }
57
59
  static {
58
- this.properties = { hasOverflowingEndTabTitle: [16, {}, { state: true }], hasOverflowingStartTabTitle: [16, {}, { state: true }], selectedTabId: [16, {}, { state: true }], bordered: [7, {}, { reflect: true, type: Boolean }], layout: [3, {}, { reflect: true }], messageOverrides: [0, {}, { attribute: false }], position: 1, scale: 1, selectedTitle: [0, {}, { attribute: false }], storageId: [3, {}, { reflect: true }], syncId: [3, {}, { reflect: true }] };
60
+ this.properties = { hasOverflowingEndTabTitle: [16, {}, { state: true }], hasOverflowingStartTabTitle: [16, {}, { state: true }], hasVisibleTabTitles: [16, {}, { state: true }], selectedTabId: [16, {}, { state: true }], bordered: [7, {}, { reflect: true, type: Boolean }], layout: [3, {}, { reflect: true }], lastTabClosable: [5, {}, { type: Boolean }], messageOverrides: [0, {}, { attribute: false }], position: 1, scale: 1, selectedTitle: [0, {}, { attribute: false }], storageId: [3, {}, { reflect: true }], syncId: [3, {}, { reflect: true }] };
59
61
  }
60
62
  static {
61
63
  this.styles = styles;
@@ -76,7 +78,7 @@ class TabNav extends LitElement {
76
78
  }
77
79
  }
78
80
  willUpdate(changes) {
79
- if (changes.has("selectedTitle") && (this.hasUpdated || this.selectedTitle !== null)) {
81
+ if (changes.has("selectedTitle") && (this.hasUpdated || this.selectedTitle !== null) && this.selectedTabId !== void 0) {
80
82
  this.calciteInternalTabChange.emit({
81
83
  tab: this.selectedTabId
82
84
  });
@@ -84,6 +86,9 @@ class TabNav extends LitElement {
84
86
  if (changes.has("selectedTabId")) {
85
87
  this.selectedTabIdChanged();
86
88
  }
89
+ if (changes.has("lastTabClosable") && this.hasUpdated) {
90
+ this.updateLastVisibleTabClosable();
91
+ }
87
92
  const { parentTabsEl } = this;
88
93
  if (parentTabsEl) {
89
94
  this.layout = parentTabsEl.layout;
@@ -93,7 +98,7 @@ class TabNav extends LitElement {
93
98
  }
94
99
  loaded() {
95
100
  this.scrollTabTitleIntoView(this.selectedTitle, "instant");
96
- if (this.tabTitles.length && this.tabTitles.every((title) => !title.selected) && !this.selectedTabId) {
101
+ if (this.tabTitles.length && this.tabTitles.every((title) => !title.selected) && this.selectedTabId === void 0) {
97
102
  this.tabTitles[0].getTabIdentifier().then((tab) => {
98
103
  this.calciteInternalTabChange.emit({
99
104
  tab
@@ -169,6 +174,7 @@ class TabNav extends LitElement {
169
174
  this.selectedTabId = event.detail;
170
175
  this.selectedTitle = await this.getTabTitleById(this.selectedTabId);
171
176
  }
177
+ this.syncVisibleTabTitlesState();
172
178
  }
173
179
  globalInternalTabChangeHandler(event) {
174
180
  if (this.syncId && event.target !== this.el && event.target.syncId === this.syncId && this.selectedTabId !== event.detail.tab) {
@@ -178,7 +184,10 @@ class TabNav extends LitElement {
178
184
  }
179
185
  async selectedTabIdChanged() {
180
186
  await this.componentOnReady();
181
- if (localStorage && this.storageId && this.selectedTabId !== void 0 && this.selectedTabId !== null) {
187
+ if (this.selectedTabId === void 0) {
188
+ return;
189
+ }
190
+ if (localStorage && this.storageId) {
182
191
  localStorage.setItem(`calcite-tab-nav-${this.storageId}`, JSON.stringify(this.selectedTabId));
183
192
  }
184
193
  this.calciteInternalTabChange.emit({
@@ -209,13 +218,33 @@ class TabNav extends LitElement {
209
218
  tabTitles.forEach((child) => {
210
219
  this.intersectionObserver?.observe(child);
211
220
  });
221
+ this.syncVisibleTabTitlesState();
222
+ }
223
+ syncVisibleTabTitlesState() {
224
+ this.updateLastVisibleTabClosable();
225
+ this.hasVisibleTabTitles = this.getVisibleTabTitlesIndices(this.tabTitles).length > 0;
226
+ this.calciteInternalTabNavSlotChange.emit([...this.tabTitles]);
227
+ }
228
+ updateLastVisibleTabClosable() {
229
+ const { tabTitles } = this;
212
230
  const visibleTabTitlesIndices = this.getVisibleTabTitlesIndices(tabTitles);
213
231
  const totalVisibleTabTitles = visibleTabTitlesIndices.length;
214
- if (totalVisibleTabTitles > 1 && this.makeFirstVisibleTabClosable) {
215
- tabTitles[visibleTabTitlesIndices[0]].closable = true;
216
- this.makeFirstVisibleTabClosable = false;
232
+ if (totalVisibleTabTitles === 0) {
233
+ return;
234
+ }
235
+ const firstVisibleTabTitle = tabTitles[visibleTabTitlesIndices[0]];
236
+ const shouldDisableCloseButton = !this.lastTabClosable && totalVisibleTabTitles === 1;
237
+ if (shouldDisableCloseButton) {
238
+ if (firstVisibleTabTitle.closable) {
239
+ this.firstVisibleTabMadeNonClosable = firstVisibleTabTitle;
240
+ firstVisibleTabTitle.closable = false;
241
+ }
242
+ return;
243
+ }
244
+ if (this.firstVisibleTabMadeNonClosable && !this.firstVisibleTabMadeNonClosable.closed) {
245
+ this.firstVisibleTabMadeNonClosable.closable = true;
217
246
  }
218
- this.calciteInternalTabNavSlotChange.emit(tabTitles);
247
+ this.firstVisibleTabMadeNonClosable = void 0;
219
248
  }
220
249
  setTabTitleContainerEl(el) {
221
250
  this.tabTitleContainerEl = el;
@@ -334,26 +363,35 @@ class TabNav extends LitElement {
334
363
  }
335
364
  handleTabTitleClose(closedTabTitleEl) {
336
365
  const { tabTitles } = this;
366
+ const visibleTabTitles = tabTitles.filter((tabTitle) => !tabTitle.closed);
367
+ const enabledVisibleTabTitles = this.enabledTabTitles;
368
+ const totalVisibleTabTitles = visibleTabTitles.length;
337
369
  const selectionModified = closedTabTitleEl.selected;
338
- const visibleTabTitlesIndices = this.getVisibleTabTitlesIndices(tabTitles);
339
- const totalVisibleTabTitles = visibleTabTitlesIndices.length;
340
- if (totalVisibleTabTitles === 1 && tabTitles[visibleTabTitlesIndices[0]].closable) {
341
- this.makeFirstVisibleTabClosable = true;
342
- tabTitles[visibleTabTitlesIndices[0]].closable = false;
343
- this.selectedTabId = visibleTabTitlesIndices[0];
344
- if (selectionModified) {
345
- tabTitles[visibleTabTitlesIndices[0]].activateTab();
346
- }
347
- } else if (totalVisibleTabTitles > 1) {
370
+ this.hasVisibleTabTitles = totalVisibleTabTitles > 0;
371
+ this.calciteInternalTabNavSlotChange.emit([...tabTitles]);
372
+ if (totalVisibleTabTitles === 0) {
373
+ this.selectedTitle = null;
374
+ this.selectedTabId = void 0;
375
+ return;
376
+ }
377
+ if (selectionModified) {
348
378
  const closedTabTitleIndex = tabTitles.findIndex((el) => el === closedTabTitleEl);
349
- const nextTabTitleIndex = visibleTabTitlesIndices.find((value) => value > closedTabTitleIndex);
350
- if (this.selectedTabId === closedTabTitleIndex) {
351
- this.selectedTabId = nextTabTitleIndex ? nextTabTitleIndex : totalVisibleTabTitles - 1;
352
- tabTitles[this.selectedTabId].activateTab();
379
+ const nextVisibleTabTitle = enabledVisibleTabTitles.find((tabTitle) => tabTitles.indexOf(tabTitle) > closedTabTitleIndex) || enabledVisibleTabTitles.at(-1);
380
+ if (!nextVisibleTabTitle) {
381
+ this.selectedTitle = null;
382
+ this.selectedTabId = void 0;
383
+ this.updateLastVisibleTabClosable();
384
+ return;
353
385
  }
386
+ nextVisibleTabTitle.activateTab();
354
387
  }
388
+ this.updateLastVisibleTabClosable();
355
389
  requestAnimationFrame(() => {
356
- focusElement(tabTitles[this.selectedTabId]);
390
+ const selectedTitle = this.selectedTitle;
391
+ if (!selectedTitle) {
392
+ return;
393
+ }
394
+ focusElement(selectedTitle);
357
395
  });
358
396
  }
359
397
  render() {
@@ -363,7 +401,7 @@ class TabNav extends LitElement {
363
401
  [CSS.scale(this.scale)]: true,
364
402
  [CSS.position(this.position)]: true,
365
403
  [CSS_UTILITY.rtl]: this.effectiveDir === "rtl"
366
- })}><div class=${safeClassMap({
404
+ })} .hidden=${!this.hasVisibleTabTitles}><div class=${safeClassMap({
367
405
  [CSS.tabTitleSlotWrapper]: true
368
406
  })} @scroll=${this.onTabTitleScroll} @wheel=${this.onTabTitleWheel} ${ref(this.setTabTitleContainerEl)}><slot @slotchange=${this.onSlotChange}></slot></div><div class=${safeClassMap(CSS.scrollButtonContainer)} .hidden=${!this.hasOverflowingEndTabTitle && !this.hasOverflowingStartTabTitle}>${this.renderScrollButton("start")}${this.renderScrollButton("end")}</div></div>`;
369
407
  }
@@ -54,6 +54,7 @@ class TabTitle extends LitElement {
54
54
  this.selected = false;
55
55
  this.calciteInternalTabIconChanged = createEvent({ cancelable: false });
56
56
  this.calciteInternalTabTitleRegister = createEvent({ cancelable: false });
57
+ this.calciteInternalTabTitleCloseChange = createEvent({ cancelable: false });
57
58
  this.calciteInternalTabsActivate = createEvent({ cancelable: false });
58
59
  this.calciteInternalTabsClose = createEvent({ cancelable: false });
59
60
  this.calciteInternalTabsFocusFirst = createEvent({ cancelable: false });
@@ -108,6 +109,9 @@ class TabTitle extends LitElement {
108
109
  if (changes.has("selected") && (this.hasUpdated || this.selected !== false)) {
109
110
  this.selectedHandler();
110
111
  }
112
+ if (changes.has("closed") && this.hasUpdated) {
113
+ this.calciteInternalTabTitleCloseChange.emit();
114
+ }
111
115
  if (this.parentTabsEl) {
112
116
  this.layout = this.parentTabsEl.layout;
113
117
  this.bordered = this.parentTabsEl.bordered;
@@ -16,6 +16,12 @@ export abstract class Tabs extends LitElement {
16
16
  * @default false
17
17
  */
18
18
  accessor bordered: boolean;
19
+ /**
20
+ * When `true`, allows the last visible closable tab to keep its close button.
21
+ *
22
+ * @default false
23
+ */
24
+ accessor lastTabClosable: boolean;
19
25
  /**
20
26
  * Specifies the layout of the `calcite-tab-nav`, justifying the `calcite-tab-title`s to the start (`"inline"`), or across and centered (`"center"`).
21
27
  *
@@ -17,14 +17,16 @@ class Tabs extends LitElement {
17
17
  this.slotRef = createRef();
18
18
  this.tabs = [];
19
19
  this.titles = [];
20
+ this.hasVisibleTitles = true;
20
21
  this.bordered = false;
21
22
  this.layout = "inline";
23
+ this.lastTabClosable = false;
22
24
  this.position = "top";
23
25
  this.scale = "m";
24
26
  this.listen("calciteInternalTabNavSlotChange", this.calciteInternalTabNavSlotChangeHandler);
25
27
  }
26
28
  static {
27
- this.properties = { tabs: [16, {}, { state: true }], titles: [16, {}, { state: true }], bordered: [5, {}, { type: Boolean }], layout: [3, {}, { reflect: true }], position: [3, {}, { reflect: true }], scale: [3, {}, { reflect: true }] };
29
+ this.properties = { tabs: [16, {}, { state: true }], titles: [16, {}, { state: true }], hasVisibleTitles: [16, {}, { state: true }], bordered: [5, {}, { type: Boolean }], layout: [3, {}, { reflect: true }], lastTabClosable: [7, {}, { reflect: true, type: Boolean }], position: [3, {}, { reflect: true }], scale: [3, {}, { reflect: true }] };
28
30
  }
29
31
  static {
30
32
  this.styles = styles;
@@ -37,19 +39,22 @@ class Tabs extends LitElement {
37
39
  this.updateItems();
38
40
  }
39
41
  willUpdate(changes) {
40
- if (changes.has("position") && (this.hasUpdated || this.position !== "top") || changes.has("scale") && (this.hasUpdated || this.scale !== "m")) {
42
+ if (changes.has("position") && (this.hasUpdated || this.position !== "top") || changes.has("scale") && (this.hasUpdated || this.scale !== "m") || changes.has("lastTabClosable") && (this.hasUpdated || this.lastTabClosable !== false)) {
41
43
  this.updateItems();
42
44
  }
43
- if ((changes.has("titles") || changes.has("tabs")) && this.hasUpdated && this.titles?.length > 0 && this.tabs?.length > 0) {
45
+ if ((changes.has("titles") || changes.has("tabs")) && this.hasUpdated && (this.lastTabClosable || this.titles?.length > 0) && (this.lastTabClosable || this.tabs?.length > 0)) {
44
46
  this.updateAriaSettings();
45
47
  this.updateItems();
46
48
  }
47
49
  }
48
50
  calciteInternalTabNavSlotChangeHandler(event) {
49
51
  event.stopPropagation();
50
- if (event.detail.length !== this.titles.length) {
51
- this.titles = event.detail;
52
+ const nextTitles = [...event.detail];
53
+ const titlesChanged = nextTitles.some((title, index) => this.titles[index] !== title);
54
+ if (titlesChanged) {
55
+ this.titles = nextTitles;
52
56
  }
57
+ this.hasVisibleTitles = nextTitles.some((title) => !title.closed);
53
58
  }
54
59
  defaultSlotChangeHandler(event) {
55
60
  this.tabs = slotChangeGetAssignedElements(event, "calcite-tab");
@@ -82,9 +87,10 @@ class Tabs extends LitElement {
82
87
  this.titles.forEach((el) => el._updateAriaInfo(tabIds, titleIds));
83
88
  }
84
89
  updateItems() {
85
- const { position, scale } = this;
90
+ const { lastTabClosable, position, scale } = this;
86
91
  const nav = this.el.querySelector("calcite-tab-nav");
87
92
  if (nav) {
93
+ nav.lastTabClosable = lastTabClosable;
88
94
  nav.position = position;
89
95
  nav.scale = scale;
90
96
  }
@@ -100,7 +106,7 @@ class Tabs extends LitElement {
100
106
  });
101
107
  }
102
108
  render() {
103
- return html`<slot name=${SLOTS.titleGroup}></slot><section class=${safeClassMap(CSS.section)}><slot @slotchange=${this.defaultSlotChangeHandler} ${ref(this.slotRef)}></slot></section>`;
109
+ return html`<slot name=${SLOTS.titleGroup}></slot><section class=${safeClassMap(CSS.section)} .hidden=${!this.hasVisibleTitles}><slot @slotchange=${this.defaultSlotChangeHandler} ${ref(this.slotRef)}></slot></section>`;
104
110
  }
105
111
  }
106
112
  customElement("calcite-tabs", Tabs);