@esri/calcite-components 5.2.0-next.5 → 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 (166) hide show
  1. package/dist/cdn/{ZMMAK3SH.js → 22N7ARV7.js} +1 -1
  2. package/dist/cdn/255CJNBQ.js +2 -0
  3. package/dist/cdn/{AO3P5HVZ.js → 2B5SK2B4.js} +1 -1
  4. package/dist/cdn/{DWSDEXRF.js → 2DVSDS5W.js} +1 -1
  5. package/dist/cdn/{5BZENCNG.js → 2W5AIJ3P.js} +1 -1
  6. package/dist/cdn/{JRKNYKHL.js → 2X6QZRGI.js} +1 -1
  7. package/dist/cdn/{HHE6MZFG.js → 2ZLARVHZ.js} +1 -1
  8. package/dist/cdn/{COKKZKHK.js → 37C2BTJH.js} +1 -1
  9. package/dist/cdn/{I46XWJBK.js → 3DZCTGTX.js} +1 -1
  10. package/dist/cdn/{C3PA7JRL.js → 3FM74CVY.js} +1 -1
  11. package/dist/cdn/{R7RCLEUS.js → 3IMK322V.js} +1 -1
  12. package/dist/cdn/{HFYWGKZY.js → 3ND6JJU2.js} +1 -1
  13. package/dist/cdn/{ETT4WWDK.js → 45ZL6S2L.js} +1 -1
  14. package/dist/cdn/{MPZEO75L.js → 4HQGPAC7.js} +1 -1
  15. package/dist/cdn/{OD7YQVTL.js → 4RYFAF65.js} +1 -1
  16. package/dist/cdn/{PEL5LMQA.js → 4SXYANKI.js} +1 -1
  17. package/dist/cdn/{5NRU7OJF.js → 4ZQOFYGA.js} +1 -1
  18. package/dist/cdn/{T5AZQF23.js → 5BBXVTVC.js} +1 -1
  19. package/dist/cdn/{SEFQONXQ.js → 5HP5FZAB.js} +1 -1
  20. package/dist/cdn/{7RH2SJQU.js → 5L75WHPS.js} +1 -1
  21. package/dist/cdn/{QGJHYPKZ.js → 5W44MDZE.js} +1 -1
  22. package/dist/cdn/{TYZTOEVY.js → 67HJME4D.js} +1 -1
  23. package/dist/cdn/{5Y6744HE.js → 6A6DR3VH.js} +1 -1
  24. package/dist/cdn/{OIS2OCUI.js → 6C54IW5E.js} +1 -1
  25. package/dist/cdn/{46EH3H4M.js → 6MJP7OIJ.js} +1 -1
  26. package/dist/cdn/{TTYV37HC.js → 6TCERT23.js} +1 -1
  27. package/dist/cdn/{X3DDLV2Y.js → 6VGI37NE.js} +1 -1
  28. package/dist/cdn/{5EKUTIXQ.js → 744TBMM3.js} +1 -1
  29. package/dist/cdn/{4ZNLMI7C.js → 7BIEHNBN.js} +1 -1
  30. package/dist/cdn/{J6UBJZOW.js → 7HMML2DR.js} +1 -1
  31. package/dist/cdn/{X2K2EAV2.js → 7KVOA3RG.js} +1 -1
  32. package/dist/cdn/{RNBHN3DC.js → 7QSFRDV5.js} +1 -1
  33. package/dist/cdn/{5CSUX3V5.js → AE4FA7FY.js} +1 -1
  34. package/dist/cdn/{Y3CYF4JT.js → AEUGG6UI.js} +1 -1
  35. package/dist/cdn/{HIELBAF7.js → AFLT7NPW.js} +1 -1
  36. package/dist/cdn/{Z5GDMSB2.js → AQOHIR7I.js} +1 -1
  37. package/dist/cdn/{5ZQXBBQQ.js → B5M6XZPQ.js} +1 -1
  38. package/dist/cdn/{SR455Z6P.js → BDRBFTUJ.js} +1 -1
  39. package/dist/cdn/{55RYBWXB.js → BE7SWPCI.js} +1 -1
  40. package/dist/cdn/{PQOWSFUI.js → BM7PKEQF.js} +1 -1
  41. package/dist/cdn/{QP2DLERM.js → BZR7SCVQ.js} +1 -1
  42. package/dist/cdn/{V3PU3YQV.js → C3EMHXIX.js} +1 -1
  43. package/dist/cdn/{NWEOQPRQ.js → C5A7GGD4.js} +1 -1
  44. package/dist/cdn/{KW6UJGMB.js → CA6ESPGD.js} +1 -1
  45. package/dist/cdn/{PKHPMEIN.js → CJMUF6Z7.js} +1 -1
  46. package/dist/cdn/D3VMRWYN.js +2 -0
  47. package/dist/cdn/{TH2V4WUT.js → D4HPNC3L.js} +1 -1
  48. package/dist/cdn/{EFVZRX3W.js → DHCG4KMO.js} +1 -1
  49. package/dist/cdn/{E3RCK74P.js → DS5VHI4Z.js} +1 -1
  50. package/dist/cdn/{7Y3S5Y55.js → DU34ZRAK.js} +1 -1
  51. package/dist/cdn/{YCNLKQMF.js → EEHC75BT.js} +1 -1
  52. package/dist/cdn/{ILPIQWU7.js → EHGKLR2I.js} +1 -1
  53. package/dist/cdn/{YPPRNINV.js → EIG5UNV3.js} +1 -1
  54. package/dist/cdn/{5BTPWVDT.js → EM2QRJCP.js} +1 -1
  55. package/dist/cdn/{6S2O33VJ.js → ET5QQ6ZE.js} +1 -1
  56. package/dist/cdn/{KANZL7X4.js → FHFQFLLV.js} +1 -1
  57. package/dist/cdn/{M4NJVOHB.js → FJWV33EJ.js} +1 -1
  58. package/dist/cdn/{KSCSAABI.js → FL5AI52A.js} +1 -1
  59. package/dist/cdn/{Z5OIB5PU.js → FQGP2TF4.js} +1 -1
  60. package/dist/cdn/{7BA5SO53.js → FQU67QYY.js} +1 -1
  61. package/dist/cdn/{24HIUUSA.js → GGJZTKGX.js} +1 -1
  62. package/dist/cdn/{IOFLSPTQ.js → GMEB4FUQ.js} +1 -1
  63. package/dist/cdn/{3L4DDI45.js → GQSSPVYH.js} +1 -1
  64. package/dist/cdn/{DNCMORYJ.js → GZNLRM76.js} +1 -1
  65. package/dist/cdn/{MPLVWYDA.js → GZTMMGCJ.js} +1 -1
  66. package/dist/cdn/{Y6HZAGBB.js → H7UZS446.js} +1 -1
  67. package/dist/cdn/{KZQTUYY3.js → HBLG43FI.js} +1 -1
  68. package/dist/cdn/{3CMHSLTX.js → HCQ73WZV.js} +1 -1
  69. package/dist/cdn/{QD3AIKVA.js → HEIJ72GT.js} +1 -1
  70. package/dist/cdn/{F4ZYZO6J.js → HMXCTTUK.js} +1 -1
  71. package/dist/cdn/{FTXCSWSH.js → HXT7NOOV.js} +1 -1
  72. package/dist/cdn/{FAMZWCRE.js → IHPU7EWA.js} +1 -1
  73. package/dist/cdn/{7EJ24UTN.js → IJAMTOKN.js} +1 -1
  74. package/dist/cdn/{BXU65LPT.js → J7FC6ZPY.js} +1 -1
  75. package/dist/cdn/{2TEG5UFR.js → JB4DSSHG.js} +1 -1
  76. package/dist/cdn/{REGGVDSA.js → JCW6IR2I.js} +1 -1
  77. package/dist/cdn/{F5AGI2QN.js → JI2XHUUM.js} +1 -1
  78. package/dist/cdn/{QMBCFBKX.js → JPRBZLNY.js} +1 -1
  79. package/dist/cdn/{7BR2ER3N.js → JQA4RU76.js} +1 -1
  80. package/dist/cdn/{L47IPAUB.js → KCL3KOWK.js} +1 -1
  81. package/dist/cdn/{3HX4E5AT.js → KV4UMXMD.js} +1 -1
  82. package/dist/cdn/{HJXYIWMX.js → M5GCKYUY.js} +1 -1
  83. package/dist/cdn/{MWYYOL2T.js → MDMDAT7S.js} +1 -1
  84. package/dist/cdn/{GHJCL53I.js → MEPDW4WV.js} +1 -1
  85. package/dist/cdn/{36ZG4GBQ.js → MLDTAC4V.js} +1 -1
  86. package/dist/cdn/{TOBPOAGZ.js → MO5PWDHH.js} +1 -1
  87. package/dist/cdn/{PLP76FWF.js → MWHL3FGX.js} +1 -1
  88. package/dist/cdn/{MMDRAXBD.js → N2LGKOPB.js} +1 -1
  89. package/dist/cdn/{WY3R7VLJ.js → N3XTOHD4.js} +1 -1
  90. package/dist/cdn/{EVU777DB.js → NCAFX2IU.js} +1 -1
  91. package/dist/cdn/{45ELN2PJ.js → NEBN6Q6V.js} +1 -1
  92. package/dist/cdn/{WSZT4GBO.js → NFDSCUC7.js} +1 -1
  93. package/dist/cdn/{QDVQOMAF.js → NFHPGWE3.js} +1 -1
  94. package/dist/cdn/NMBCJCCO.js +2 -0
  95. package/dist/cdn/{DHNR7VLX.js → NRYSWYNK.js} +1 -1
  96. package/dist/cdn/{KG2UEHKF.js → NU72X3HS.js} +1 -1
  97. package/dist/cdn/{G6G7V52J.js → NXUFQ4YS.js} +1 -1
  98. package/dist/cdn/{JCZW5TS2.js → O2QQXYDW.js} +1 -1
  99. package/dist/cdn/{WJ5ZTHI4.js → OFDHYKQN.js} +1 -1
  100. package/dist/cdn/{J4SYG3DY.js → OINOBLBC.js} +1 -1
  101. package/dist/cdn/{VWOB3FKQ.js → OR55DZMS.js} +1 -1
  102. package/dist/cdn/{GX6IID4J.js → ORKUIIJK.js} +1 -1
  103. package/dist/cdn/{RNPVTYW7.js → PQK6ETUC.js} +1 -1
  104. package/dist/cdn/{3PIM6BMO.js → PQLUXN7R.js} +1 -1
  105. package/dist/cdn/{NXZ67AHU.js → Q5CRHYT4.js} +1 -1
  106. package/dist/cdn/{RL6433GX.js → Q67TFS2A.js} +1 -1
  107. package/dist/cdn/{NN2IHPEX.js → QENJY6C7.js} +1 -1
  108. package/dist/cdn/{QKS7EOFA.js → QJF5YGPY.js} +1 -1
  109. package/dist/cdn/{6OC2BJBW.js → QLNBJ3D2.js} +1 -1
  110. package/dist/cdn/{HZVGGFHL.js → R35E6X4J.js} +1 -1
  111. package/dist/cdn/{LCFR6GTY.js → RBSWNTNU.js} +1 -1
  112. package/dist/cdn/{DMOGCVWZ.js → RDBTAJCH.js} +1 -1
  113. package/dist/cdn/{AK6XLW7N.js → RYR7RCAB.js} +1 -1
  114. package/dist/cdn/{IYXJEO3U.js → S5YU36AW.js} +1 -1
  115. package/dist/cdn/{ODO44U4I.js → SBWEXBSU.js} +1 -1
  116. package/dist/cdn/{4IS55ZBO.js → SEHJ4RKZ.js} +1 -1
  117. package/dist/cdn/{Q6E7AO5H.js → SRGRHGJ5.js} +1 -1
  118. package/dist/cdn/{M5TS7WI7.js → SU7BYFW3.js} +1 -1
  119. package/dist/cdn/{MCWOYBP4.js → SVJV6P4P.js} +1 -1
  120. package/dist/cdn/{7OHPGPMA.js → TOJCGSWL.js} +1 -1
  121. package/dist/cdn/{I4WD7S3Q.js → TSXOSLFT.js} +1 -1
  122. package/dist/cdn/{PRWKGDJR.js → U5NEBHS5.js} +1 -1
  123. package/dist/cdn/{SIBHS5A2.js → UES5LGVM.js} +1 -1
  124. package/dist/cdn/{BP25LS3Z.js → UJRRKIO7.js} +1 -1
  125. package/dist/cdn/{FYEPBQFF.js → UL7L5FJO.js} +1 -1
  126. package/dist/cdn/{PCVAFTNV.js → UOHGU4YY.js} +1 -1
  127. package/dist/cdn/{TNFD3HYK.js → V6FHFWKX.js} +1 -1
  128. package/dist/cdn/{322PFF7Z.js → VPVCIXE2.js} +1 -1
  129. package/dist/cdn/{O3BCYJMC.js → WEXOUBDS.js} +1 -1
  130. package/dist/cdn/{MZWGXNX4.js → WF6BMZT7.js} +1 -1
  131. package/dist/cdn/{2IU3EHCK.js → WSZFROTG.js} +1 -1
  132. package/dist/cdn/{K6XQCMHC.js → WYAVJAPT.js} +1 -1
  133. package/dist/cdn/{JSQBAVBT.js → WYOJIAFW.js} +1 -1
  134. package/dist/cdn/{O5PLNZUB.js → X37OGDUE.js} +1 -1
  135. package/dist/cdn/{244ERQCM.js → XG27KSRC.js} +1 -1
  136. package/dist/cdn/{QJ3HRQHV.js → XJ36MZLC.js} +1 -1
  137. package/dist/cdn/{HB6ZWNJ6.js → XZJNARMG.js} +1 -1
  138. package/dist/cdn/{MWLCAYYX.js → YXRKYXM3.js} +1 -1
  139. package/dist/cdn/{7ZFIBIHG.js → YZHTEJRH.js} +1 -1
  140. package/dist/cdn/{CDH5LXVD.js → Z3UI7HPY.js} +1 -1
  141. package/dist/cdn/{2PWHFBYE.js → ZEDBMSXG.js} +1 -1
  142. package/dist/cdn/{DUY5W2J3.js → ZHL36WFZ.js} +1 -1
  143. package/dist/cdn/{VQAXZFZK.js → ZMVMH3BK.js} +1 -1
  144. package/dist/cdn/{NBZOLUHH.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-dropdown/customElement.d.ts +1 -0
  148. package/dist/components/calcite-dropdown/customElement.js +1 -1
  149. package/dist/components/calcite-tab-nav/customElement.js +63 -25
  150. package/dist/components/calcite-tab-title/customElement.js +4 -0
  151. package/dist/components/calcite-tabs/customElement.d.ts +6 -0
  152. package/dist/components/calcite-tabs/customElement.js +13 -7
  153. package/dist/docs/api.json +1 -1
  154. package/dist/docs/docs.json +1 -1
  155. package/dist/docs/vscode.css-custom-data.json +1 -1
  156. package/dist/docs/vscode.html-custom-data.json +1 -1
  157. package/dist/docs/web-types.json +1 -1
  158. package/dist/loader.js +2 -2
  159. package/dist/types/lumina.d.ts +1 -1
  160. package/dist/types/preact.d.ts +1 -1
  161. package/dist/types/react.d.ts +1 -1
  162. package/dist/types/stencil.d.ts +1 -1
  163. package/package.json +2 -2
  164. package/dist/cdn/FGRTUJKR.js +0 -2
  165. package/dist/cdn/KBJCC6M3.js +0 -2
  166. package/dist/cdn/PBTE3AQR.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);