(this.tabNavEl = el)}
diff --git a/packages/calcite-components/src/components/tab-nav/usage/Basic.md b/packages/calcite-components/src/components/tab-nav/usage/Basic.md
index 6d4a68d2356..7cf407af314 100644
--- a/packages/calcite-components/src/components/tab-nav/usage/Basic.md
+++ b/packages/calcite-components/src/components/tab-nav/usage/Basic.md
@@ -1,9 +1,11 @@
-When tab-nav is the only parent, tab-title can inherit its `scale` and `position` from tab-nav:
+Tabs `scale` and `position` properties are inherited by it's child components, tab-nav and tab-title.
```html
-
- Layers
- Maps
- Data
-
+
+
+ Layers
+ Maps
+ Data
+
+
```
diff --git a/packages/calcite-components/src/components/tab-title/resources.ts b/packages/calcite-components/src/components/tab-title/resources.ts
index 477cf6c8ca4..d03df24cee7 100644
--- a/packages/calcite-components/src/components/tab-title/resources.ts
+++ b/packages/calcite-components/src/components/tab-title/resources.ts
@@ -4,8 +4,8 @@ export const CSS = {
content: "content",
contentHasText: "content--has-text",
iconEnd: "icon-end",
- iconStart: "icon-start",
iconPresent: "icon-present",
+ iconStart: "icon-start",
titleIcon: "calcite-tab-title--icon",
};
diff --git a/packages/calcite-components/src/components/tab-title/tab-title.e2e.ts b/packages/calcite-components/src/components/tab-title/tab-title.e2e.ts
index e220ccdb174..ebe7faf7f79 100644
--- a/packages/calcite-components/src/components/tab-title/tab-title.e2e.ts
+++ b/packages/calcite-components/src/components/tab-title/tab-title.e2e.ts
@@ -4,8 +4,8 @@ import { html } from "../../../support/formatting";
import { CSS } from "./resources";
describe("calcite-tab-title", () => {
- const tabTitleHtml = "
";
const tabTitleClosableHtml = "
";
+
const multiTabTitleClosableMarkup = `
@@ -41,7 +41,7 @@ describe("calcite-tab-title", () => {
const closeSelector = `calcite-tab-title >>> .${CSS.closeButton}`;
describe("renders", () => {
- renders(tabTitleHtml, { display: "block" });
+ renders("calcite-tab-title", { display: "block" });
renders(multiTabTitleClosableMarkup, { display: "flex" });
});
@@ -108,10 +108,18 @@ describe("calcite-tab-title", () => {
page = await newE2EPage();
await page.setContent(
html`
-
+
+
+ Tab 1 Title
+ Tab 2 Title
+ Tab 3 Title
+
+ Tab 1 Content
+ Tab 2 Content
+ Tab 3 Content
Text
Text
-
+
`
);
@@ -338,155 +346,6 @@ describe("calcite-tab-title", () => {
expect(activeEventSpy).toHaveReceivedEventTimes(2);
});
- describe("when parent element is tab-nav", () => {
- describe("when position is top, default", () => {
- it("should render with bottom border on hover", async () => {
- const page = await newE2EPage({
- html: `
-
- Tab 1 title
-
- `,
- });
- const element = await page.find("#for-hover");
- await element.hover();
-
- const container = await page.find("#for-hover >>> .container");
- const containerStyles = await container.getComputedStyle();
- expect(containerStyles["border-top-width"]).toEqual("0px");
- expect(containerStyles["border-bottom-width"]).not.toEqual("0px");
- });
- });
-
- describe("when position is bottom", () => {
- it("should render with top border on hover", async () => {
- const page = await newE2EPage({
- html: `
-
- Tab 1 Title
- Tab 2 Title
-
- `,
- });
- const element = await page.find("#for-hover");
- await element.hover();
-
- const container = await page.find("#for-hover >>> .container");
- const containerStyles = await container.getComputedStyle();
- expect(containerStyles["border-top-width"]).not.toEqual("0px");
- expect(containerStyles["border-bottom-width"]).toEqual("0px");
- });
- });
-
- describe("scale property", () => {
- let page: E2EPage;
-
- beforeEach(async () => {
- page = await newE2EPage();
- });
-
- it("should inherit default medium scale from tab-nav", async () => {
- await page.setContent(
- html`
-
- Tab Title
- Tab 2 Title
-
- `
- );
-
- const tabTitleNav = await page.find("calcite-tab-nav");
- const tabTitleEl = await page.find("calcite-tab-title");
- const content = await page.find(`calcite-tab-title >>> .${CSS.content}`);
- const contentStyles = await content.getComputedStyle();
-
- expect(tabTitleEl).toEqualAttribute("scale", "m");
- expect(tabTitleNav).toEqualAttribute("scale", "m");
- expect(contentStyles.fontSize).toEqual("14px");
- expect(contentStyles.lineHeight).toEqual("16px");
- });
-
- it("should inherit small scale from tab-nav", async () => {
- await page.setContent(
- html`
-
- Tab Title
- Tab 2 Title
-
- `
- );
-
- const tabTitleNav = await page.find("calcite-tab-nav");
- const tabTitleEl = await page.find("calcite-tab-title");
- const content = await page.find(`calcite-tab-title >>> .${CSS.content}`);
- const contentStyles = await content.getComputedStyle();
-
- expect(tabTitleEl).toEqualAttribute("scale", "s");
- expect(tabTitleNav).toEqualAttribute("scale", "s");
- expect(contentStyles.fontSize).toEqual("12px");
- expect(contentStyles.lineHeight).toEqual("16px");
- });
-
- it("should inherit large scale from tab-nav", async () => {
- await page.setContent(
- html`
-
- Tab Title
- Tab 2 Title
-
- `
- );
-
- const tabTitleNav = await page.find("calcite-tab-nav");
- const tabTitleEl = await page.find("calcite-tab-title");
- const content = await page.find(`calcite-tab-title >>> .${CSS.content}`);
- const contentStyles = await content.getComputedStyle();
-
- expect(tabTitleEl).toEqualAttribute("scale", "l");
- expect(tabTitleNav).toEqualAttribute("scale", "l");
- expect(contentStyles.fontSize).toEqual("16px");
- expect(contentStyles.lineHeight).toEqual("20px");
- });
- });
- });
-
- describe("when parent element is tabs", () => {
- describe("scale property", () => {
- it("should inherit default m scale", async () => {
- const page = await newE2EPage({
- html: `
- Tab Title
- Tab 2 Title
- `,
- });
- const element = await page.find("calcite-tab-title");
- expect(element).toEqualAttribute("scale", "m");
- });
-
- it("should inherit small scale from tabs", async () => {
- const page = await newE2EPage({
- html: `
- Tab Title
- Tab 2 Title
- `,
- });
- const element = await page.find("calcite-tab-title");
- expect(element).toEqualAttribute("scale", "s");
- });
-
- it("should inherit large scale from tabs", async () => {
- const page = await newE2EPage({
- html: `
- Tab 1 Title
- Tab 2 Title
- `,
- });
- const element = await page.find("calcite-tab-title");
- expect(element).toEqualAttribute("scale", "l");
- });
- });
- });
-
describe("when the active tab-title changes", () => {
it("should move the active tab nav indicator", async () => {
const page = await newE2EPage({
diff --git a/packages/calcite-components/src/components/tab-title/tab-title.scss b/packages/calcite-components/src/components/tab-title/tab-title.scss
index 275cce426ea..9baf21af777 100644
--- a/packages/calcite-components/src/components/tab-title/tab-title.scss
+++ b/packages/calcite-components/src/components/tab-title/tab-title.scss
@@ -1,14 +1,20 @@
:host {
- @apply block flex-initial outline-none;
+ @apply block outline-none;
margin-inline-start: theme("margin.0");
- margin-inline-end: theme("margin.5");
}
-:host([layout="center"][scale="s"]),
-:host([layout="center"][scale="m"]),
-:host([layout="center"][scale="l"]) {
+:host([layout="inline"]) {
+ @apply flex-initial;
+}
+
+:host([layout="center"]) {
+ @apply flex-auto;
+}
+
+:host([layout="center"]) .scale-s,
+:host([layout="center"]) .scale-m,
+:host([layout="center"]) .scale-l {
@apply my-0 text-center;
- margin-inline-end: theme("margin.0");
flex-basis: theme("spacing.48");
.content {
@apply m-auto;
@@ -22,25 +28,25 @@
}
}
-:host([layout="center"][bordered][closable][scale="s"]) {
+:host([layout="center"][bordered][closable]) .scale-s {
.content {
padding-inline-start: 36px; //28px button width + 0.5rem padding
}
}
-:host([layout="center"][bordered][closable][scale="m"]) {
+:host([layout="center"][bordered][closable]) .scale-m {
.content {
padding-inline-start: 40px; //28px button width + 0.75rem padding
}
}
-:host([layout="center"][closable][scale="l"]) {
+:host([layout="center"][closable]) .scale-l {
.content {
padding-inline-start: 40px; //36px button width + .25 padding
}
}
-:host([layout="center"][closable][bordered][scale="l"]) {
+:host([layout="center"][closable][bordered]) .scale-s {
.content {
padding-inline-start: 52px; //36px button width + 1rem padding
}
@@ -87,21 +93,19 @@
}
}
-:host([scale="s"]) {
- margin-inline-end: 1rem;
+.scale-s {
.content {
@apply text-n2h py-1;
}
}
-:host([scale="m"]) {
+.scale-m {
.content {
@apply text-n1h py-2;
}
}
-:host([scale="l"]) {
- margin-inline-end: 1.5rem;
+.scale-l {
.content {
@apply text-0h py-2.5;
}
@@ -255,13 +259,13 @@
}
}
-:host([bordered][scale="s"]) {
+:host([bordered]) .scale-s {
.content {
@apply px-2;
}
}
-:host([bordered][scale="l"]) {
+:host([bordered]) .scale-l {
.content {
@apply px-4;
}
diff --git a/packages/calcite-components/src/components/tab-title/tab-title.tsx b/packages/calcite-components/src/components/tab-title/tab-title.tsx
index b5ef893b4cd..89ecddc91e2 100644
--- a/packages/calcite-components/src/components/tab-title/tab-title.tsx
+++ b/packages/calcite-components/src/components/tab-title/tab-title.tsx
@@ -13,7 +13,7 @@ import {
VNode,
Watch,
} from "@stencil/core";
-import { getElementDir, getElementProp, toAriaBoolean, nodeListToArray } from "../../utils/dom";
+import { getElementDir, toAriaBoolean, nodeListToArray } from "../../utils/dom";
import { guid } from "../../utils/guid";
import {
connectInteractive,
@@ -95,14 +95,18 @@ export class TabTitle implements InteractiveComponent, LocalizedComponent, T9nCo
@Prop({ reflect: true, mutable: true }) layout: TabLayout;
/**
- * @internal
+ * Specifies the position of `calcite-tab-nav` and `calcite-tab-title` components in relation to, and is inherited from the parent `calcite-tabs`, defaults to `top`.
+ *
+ * @internal
*/
- @Prop({ reflect: true, mutable: true }) position: TabPosition;
+ @Prop() position: TabPosition = "top";
/**
+ * Specifies the size of the component inherited from the parent `calcite-tabs`, defaults to `m`.
+ *
* @internal
*/
- @Prop({ reflect: true, mutable: true }) scale: Scale;
+ @Prop() scale: Scale = "m";
/**
* @internal
@@ -177,15 +181,8 @@ export class TabTitle implements InteractiveComponent, LocalizedComponent, T9nCo
componentWillRender(): void {
if (this.parentTabsEl) {
this.layout = this.parentTabsEl.layout;
- this.position = this.parentTabsEl.position;
- this.scale = this.parentTabsEl.scale;
this.bordered = this.parentTabsEl.bordered;
}
- // handle case when tab-nav is only parent
- if (!this.parentTabsEl && this.parentTabNavEl) {
- this.position = getElementProp(this.parentTabNavEl, "position", this.position);
- this.scale = getElementProp(this.parentTabNavEl, "scale", this.scale);
- }
}
render(): VNode {
@@ -222,6 +219,7 @@ export class TabTitle implements InteractiveComponent, LocalizedComponent, T9nCo
class={{
container: true,
[CSS.iconPresent]: !!this.iconStart || !!this.iconEnd,
+ [`scale-${this.scale}`]: true,
}}
hidden={closed}
// eslint-disable-next-line react/jsx-sort-props -- ref should be last so node attrs/props are in sync (see https://github.com/Esri/calcite-design-system/pull/6530)
diff --git a/packages/calcite-components/src/components/tab/resources.ts b/packages/calcite-components/src/components/tab/resources.ts
new file mode 100644
index 00000000000..bf868fd865c
--- /dev/null
+++ b/packages/calcite-components/src/components/tab/resources.ts
@@ -0,0 +1,4 @@
+export const CSS = {
+ container: "container",
+ content: "content",
+};
diff --git a/packages/calcite-components/src/components/tab/tab.e2e.ts b/packages/calcite-components/src/components/tab/tab.e2e.ts
index 655cac5935d..1ff8bf0a3de 100644
--- a/packages/calcite-components/src/components/tab/tab.e2e.ts
+++ b/packages/calcite-components/src/components/tab/tab.e2e.ts
@@ -1,4 +1,3 @@
-import { newE2EPage } from "@stencil/core/testing";
import { defaults, renders, hidden } from "../../tests/commonTests";
describe("calcite-tab", () => {
@@ -18,43 +17,7 @@ describe("calcite-tab", () => {
defaults("calcite-tab", [
{ propertyName: "tab", defaultValue: undefined },
{ propertyName: "selected", defaultValue: false },
- { propertyName: "scale", defaultValue: undefined },
+ { propertyName: "scale", defaultValue: "m" },
]);
});
-
- describe("when nested within calcite-tabs component", () => {
- it("should render with medium scale", async () => {
- const page = await newE2EPage({
- html: `
${tabHtml}`,
- });
- const element = await page.find("calcite-tab");
- expect(element).toEqualAttribute("scale", "m");
- expect(await (await element.getComputedStyle())["font-size"]).toEqual("14px");
- expect(await (await element.getComputedStyle())["line-height"]).toEqual("16px"); // 1rem
- });
-
- describe("when tabs scale is small", () => {
- it("should render with small scale", async () => {
- const page = await newE2EPage({
- html: `
${tabHtml}`,
- });
- const element = await page.find("calcite-tab");
- expect(element).toEqualAttribute("scale", "s");
- expect(await (await element.getComputedStyle())["font-size"]).toEqual("12px");
- expect(await (await element.getComputedStyle())["line-height"]).toEqual("16px"); // 1rem
- });
- });
-
- describe("when tabs scale is large", () => {
- it("should render with large scale", async () => {
- const page = await newE2EPage({
- html: `
${tabHtml}`,
- });
- const element = await page.find("calcite-tab");
- expect(element).toEqualAttribute("scale", "l");
- expect(await (await element.getComputedStyle())["font-size"]).toEqual("16px");
- expect(await (await element.getComputedStyle())["line-height"]).toEqual("20px"); // 1.25rem
- });
- });
- });
});
diff --git a/packages/calcite-components/src/components/tab/tab.scss b/packages/calcite-components/src/components/tab/tab.scss
index a7236a5114a..1a794bcdf7b 100644
--- a/packages/calcite-components/src/components/tab/tab.scss
+++ b/packages/calcite-components/src/components/tab/tab.scss
@@ -13,22 +13,21 @@
@apply block h-full w-full overflow-auto;
}
-section,
-.container {
- @apply hidden h-full w-full;
-}
-
-:host([scale="s"]) {
+.scale-s .content {
@apply text-n2h py-1;
}
-:host([scale="m"]) {
+.scale-m .content {
@apply text-n1h py-2;
}
-:host([scale="l"]) {
- @apply text-0h;
- padding-block: 13px;
+.scale-l .content {
+ @apply text-0h py-2.5;
+}
+
+section,
+.container {
+ @apply hidden h-full w-full;
}
@include base-component();
diff --git a/packages/calcite-components/src/components/tab/tab.tsx b/packages/calcite-components/src/components/tab/tab.tsx
index adcccd6a986..3f0f456bdbc 100644
--- a/packages/calcite-components/src/components/tab/tab.tsx
+++ b/packages/calcite-components/src/components/tab/tab.tsx
@@ -11,6 +11,7 @@ import {
State,
VNode,
} from "@stencil/core";
+import { CSS } from "./resources";
import { nodeListToArray } from "../../utils/dom";
import { guid } from "../../utils/guid";
import { Scale } from "../interfaces";
@@ -46,9 +47,11 @@ export class Tab {
@Prop({ reflect: true, mutable: true }) selected = false;
/**
+ * Specifies the size of the component inherited from the parent `calcite-tabs`, defaults to `m`.
+ *
* @internal
*/
- @Prop({ reflect: true, mutable: true }) scale: Scale = "m";
+ @Prop() scale: Scale = "m";
//--------------------------------------------------------------------------
//
@@ -61,8 +64,12 @@ export class Tab {
return (
-
-
+
+
@@ -78,10 +85,6 @@ export class Tab {
this.calciteInternalTabRegister.emit();
}
- componentWillRender(): void {
- this.scale = this.parentTabsEl?.scale;
- }
-
disconnectedCallback(): void {
// Dispatching to body in order to be listened by other elements that are still connected to the DOM.
document.body?.dispatchEvent(
diff --git a/packages/calcite-components/src/components/tabs/tabs.e2e.ts b/packages/calcite-components/src/components/tabs/tabs.e2e.ts
index 8dbe5ff3f59..ef294223871 100644
--- a/packages/calcite-components/src/components/tabs/tabs.e2e.ts
+++ b/packages/calcite-components/src/components/tabs/tabs.e2e.ts
@@ -1,10 +1,12 @@
import { newE2EPage } from "@stencil/core/testing";
import { html } from "../../../support/formatting";
-import { accessible, defaults, hidden, renders } from "../../tests/commonTests";
+import { accessible, defaults, hidden, reflects, renders } from "../../tests/commonTests";
import { GlobalTestProps } from "../../tests/utils";
+import { Scale } from "../interfaces";
+import { TabPosition } from "../tabs/interfaces";
describe("calcite-tabs", () => {
- const tabsContent = `
+ const tabsContent = html`
Tab 1 Title
Tab 2 Title
@@ -16,7 +18,7 @@ describe("calcite-tabs", () => {
Tab 3 Content
Tab 4 Content
`;
- const tabsSnippet = `${tabsContent}`;
+ const tabsSnippet = html`${tabsContent}`;
describe("renders", () => {
renders(tabsSnippet, { display: "flex" });
@@ -34,6 +36,14 @@ describe("calcite-tabs", () => {
]);
});
+ describe("reflects", () => {
+ reflects("calcite-tabs", [
+ { propertyName: "layout", value: "inline" },
+ { propertyName: "position", value: "top" },
+ { propertyName: "scale", value: "m" },
+ ]);
+ });
+
describe("accessible: checked", () => {
accessible(`${tabsContent}`);
});
@@ -117,47 +127,37 @@ describe("calcite-tabs", () => {
}
});
- describe("when no scale is provided", () => {
- it("should render itself and child tab elements with default medium scale", async () => {
- const page = await newE2EPage({
- html: `${tabsContent}`,
- });
- expect(await page.find("calcite-tabs")).toEqualAttribute("scale", "m");
- expect(await page.find("calcite-tab-nav")).toEqualAttribute("scale", "m");
- expect(await page.find("calcite-tab-title")).toEqualAttribute("scale", "m");
- expect(await page.find("calcite-tab")).toEqualAttribute("scale", "m");
- });
- });
-
- describe("when scale is provided", () => {
- it("should render itself and child tab elements with corresponding scale (small)", async () => {
- const page = await newE2EPage({
- html: `${tabsContent}`,
- });
- expect(await page.find("calcite-tabs")).toEqualAttribute("scale", "s");
- expect(await page.find("calcite-tab-nav")).toEqualAttribute("scale", "s");
- expect(await page.find("calcite-tab-title")).toEqualAttribute("scale", "s");
- expect(await page.find("calcite-tab")).toEqualAttribute("scale", "s");
+ function testTabsScaleAndPosition(scale: Scale, position: TabPosition) {
+ const scaleName = scale === "m" ? "default medium" : scale;
+
+ it(`should render itself and child tab elements with corresponding scale (${scaleName}) and position (${position})`, async () => {
+ const page = await newE2EPage();
+ await page.setContent(html`${tabsContent}`);
+ await page.waitForChanges();
+
+ const tabs = await page.find("calcite-tabs");
+ const tab = await page.find("calcite-tab");
+ const tabTitle = await page.find("calcite-tab-title");
+ const tabNav = await page.find("calcite-tab-nav");
+
+ expect(await tabs.getProperty("scale")).toBe(scale);
+ expect(await tabs.getProperty("position")).toBe(position);
+ expect(await tabNav.getProperty("scale")).toBe(scale);
+ expect(await tabNav.getProperty("position")).toBe(position);
+ expect(await tabTitle.getProperty("scale")).toBe(scale);
+ expect(await tabTitle.getProperty("position")).toBe(position);
+ expect(await tab.getProperty("scale")).toBe(scale);
});
+ }
- it("should render itself and child tab elements with corresponding scale (medium)", async () => {
- const page = await newE2EPage({
- html: `${tabsContent}`,
- });
- expect(await page.find("calcite-tabs")).toEqualAttribute("scale", "m");
- expect(await page.find("calcite-tab-nav")).toEqualAttribute("scale", "m");
- expect(await page.find("calcite-tab-title")).toEqualAttribute("scale", "m");
- expect(await page.find("calcite-tab")).toEqualAttribute("scale", "m");
- });
+ describe("calcite-tabs inheritable props", () => {
+ const scales: Scale[] = ["s", "m", "l"];
+ const positions: TabPosition[] = ["top", "bottom"];
- it("should render itself and child tab elements with corresponding scale (large)", async () => {
- const page = await newE2EPage({
- html: `${tabsContent}`,
+ scales.forEach((scale) => {
+ positions.forEach((position) => {
+ testTabsScaleAndPosition(scale, position);
});
- expect(await page.find("calcite-tabs")).toEqualAttribute("scale", "l");
- expect(await page.find("calcite-tab-nav")).toEqualAttribute("scale", "l");
- expect(await page.find("calcite-tab-title")).toEqualAttribute("scale", "l");
- expect(await page.find("calcite-tab")).toEqualAttribute("scale", "l");
});
});
@@ -258,11 +258,25 @@ describe("calcite-tabs", () => {
document.body.innerHTML = `<${wrapperName}>${wrapperName}>`;
const wrapper = document.querySelector(wrapperName);
+
+ async function waitForAnimationFrames(count) {
+ async function frame() {
+ if (count > 0) {
+ await new Promise((resolve) => requestAnimationFrame(resolve));
+ count--;
+ await frame();
+ }
+ }
+
+ await frame();
+ }
+
wrapper.shadowRoot.querySelector("#title-2").click();
- await new Promise((resolve) => requestAnimationFrame(() => resolve()));
- await new Promise((resolve) => requestAnimationFrame(() => resolve()));
+ await waitForAnimationFrames(4);
const tabTitle = wrapper.shadowRoot.querySelector("calcite-tab-title[selected]").id;
+ await waitForAnimationFrames(2);
+
const tab = wrapper.shadowRoot.querySelector("calcite-tab[selected]").id;
return { tabTitle, tab };
},
diff --git a/packages/calcite-components/src/components/tabs/tabs.stories.ts b/packages/calcite-components/src/components/tabs/tabs.stories.ts
index f7e8ac5ef76..d7497dc1af1 100644
--- a/packages/calcite-components/src/components/tabs/tabs.stories.ts
+++ b/packages/calcite-components/src/components/tabs/tabs.stories.ts
@@ -163,16 +163,94 @@ export const setWidth = (): string => html`
`;
-export const justTabNav = (): string => html`
-
+const TabNavHTMLSimple = html`
+
Tab 1 Title
Tab 2 Title
Tab 3 Title
Tab 4 Title
+ Tab 1 Content
+ Tab 2 Content
+ Tab 3 Content
+ Tab 4 Content
+`;
+
+const TabNavHTMLVariedTabWidth = html`
+
+ Tab 1 Title
+ Tab 2 Title
+ Tab 3 Title
+ Tab 4 Title
+
+ Tab 1 Content
+ Tab 2 Content
+ Tab 3 Content
+ Tab 4 Content
+`;
+
+const tabStyles = html`
+
+`;
+
+export const centerScale_TestOnly = (): string => html`
+ ${tabStyles}
+ ${TabNavHTMLSimple}
+ ${TabNavHTMLSimple}
+ ${TabNavHTMLSimple}
+`;
+
+export const centerVariedTabWidthScale_TestOnly = (): string => html`
+ ${tabStyles}
+ ${TabNavHTMLVariedTabWidth}
+ ${TabNavHTMLVariedTabWidth}
+ ${TabNavHTMLVariedTabWidth}
+`;
+
+export const centerBorderedScale_TestOnly = (): string => html`
+ ${tabStyles}
+ ${TabNavHTMLSimple}
+ ${TabNavHTMLSimple}
+ ${TabNavHTMLSimple}
+`;
+
+export const centerBorderedVariedTabWidthScale_TestOnly = (): string => html`
+ ${tabStyles}
+ ${TabNavHTMLVariedTabWidth}
+ ${TabNavHTMLVariedTabWidth}
+ ${TabNavHTMLVariedTabWidth}
+`;
+
+export const inlineScale_TestOnly = (): string => html`
+ ${tabStyles}
+ ${TabNavHTMLSimple}
+ ${TabNavHTMLSimple}
+ ${TabNavHTMLSimple}
+`;
+
+export const inlineVariedTabWidthScale_TestOnly = (): string => html`
+ ${tabStyles}
+ ${TabNavHTMLVariedTabWidth}
+ ${TabNavHTMLVariedTabWidth}
+ ${TabNavHTMLVariedTabWidth}
+`;
+
+export const inlineBorderedScale_TestOnly = (): string => html`
+ ${tabStyles}
+ ${TabNavHTMLSimple}
+ ${TabNavHTMLSimple}
+ ${TabNavHTMLSimple}
+`;
+
+export const inlineBorderedVariedTabWidthScale_TestOnly = (): string => html`
+ ${tabStyles}
+ ${TabNavHTMLVariedTabWidth}
+ ${TabNavHTMLVariedTabWidth}
+ ${TabNavHTMLVariedTabWidth}
`;
export const disabledTabsAndMediumIconsForLargeTabsTitle_TestOnly = (): string => html`
diff --git a/packages/calcite-components/src/components/tabs/tabs.tsx b/packages/calcite-components/src/components/tabs/tabs.tsx
index b900fb24ec6..79002c559c6 100644
--- a/packages/calcite-components/src/components/tabs/tabs.tsx
+++ b/packages/calcite-components/src/components/tabs/tabs.tsx
@@ -1,7 +1,8 @@
-import { Component, Element, Fragment, h, Listen, Prop, State, VNode } from "@stencil/core";
+import { Component, Element, Fragment, h, Listen, Prop, State, VNode, Watch } from "@stencil/core";
import { Scale } from "../interfaces";
import { TabLayout, TabPosition } from "./interfaces";
import { SLOTS } from "./resources";
+import { createObserver } from "../../utils/observers";
/**
* @slot - A slot for adding `calcite-tab`s.
@@ -25,15 +26,21 @@ export class Tabs {
@Prop({ reflect: true }) layout: TabLayout = "inline";
/**
- * Specifies the position of the component in relation to the `calcite-tab`s.
+ * Specifies the position of `calcite-tab-nav` and `calcite-tab-title` components in relation to the `calcite-tabs`, defaults to `top`.
*/
@Prop({ reflect: true }) position: TabPosition = "top";
/**
- * Specifies the size of the component.
+ * Specifies the size of the component, defaults to `m`.
*/
@Prop({ reflect: true }) scale: Scale = "m";
+ @Watch("position")
+ @Watch("scale")
+ handleInheritableProps(): void {
+ this.updateItems();
+ }
+
/**
* When `true`, the component will display with a folder style menu.
*/
@@ -45,6 +52,19 @@ export class Tabs {
//
//--------------------------------------------------------------------------
+ connectedCallback(): void {
+ this.mutationObserver.observe(this.el, { childList: true });
+ this.updateItems();
+ }
+
+ async componentWillLoad(): Promise {
+ this.updateItems();
+ }
+
+ disconnectedCallback(): void {
+ this.mutationObserver?.disconnect();
+ }
+
render(): VNode {
return (
@@ -133,6 +153,42 @@ export class Tabs {
*/
@State() tabs: HTMLCalciteTabElement[] = [];
+ mutationObserver = createObserver("mutation", (mutationsList: MutationRecord[]) => {
+ for (const mutation of mutationsList) {
+ const target = mutation.target as HTMLElement;
+ if (
+ target.nodeName === "CALCITE-TAB-NAV" ||
+ target.nodeName === "CALCITE-TAB-TITLE" ||
+ target.nodeName === "CALCITE-TAB"
+ ) {
+ this.updateItems();
+ }
+ }
+ });
+
+ private updateItems(): void {
+ const { position, scale } = this;
+
+ const nav = this.el.querySelector("calcite-tab-nav");
+ if (nav) {
+ nav.position = position;
+ nav.scale = scale;
+ }
+
+ Array.from(this.el.querySelectorAll("calcite-tab")).forEach((tab: HTMLCalciteTabElement) => {
+ if (tab.parentElement === this.el) {
+ tab.scale = scale;
+ }
+ });
+
+ Array.from(this.el.querySelectorAll("calcite-tab-nav > calcite-tab-title")).forEach(
+ (title: HTMLCalciteTabTitleElement) => {
+ title.position = position;
+ title.scale = scale;
+ }
+ );
+ }
+
//--------------------------------------------------------------------------
//
// Private Methods