diff --git a/cypress/apps/angular-app/src/app/app.component.html b/cypress/apps/angular-app/src/app/app.component.html
index 410e2479..8c7b57f9 100644
--- a/cypress/apps/angular-app/src/app/app.component.html
+++ b/cypress/apps/angular-app/src/app/app.component.html
@@ -14,6 +14,7 @@
+
diff --git a/cypress/apps/angular-app/src/app/app.module.ts b/cypress/apps/angular-app/src/app/app.module.ts
index 9e74afdd..ba217c28 100644
--- a/cypress/apps/angular-app/src/app/app.module.ts
+++ b/cypress/apps/angular-app/src/app/app.module.ts
@@ -1,4 +1,3 @@
-import "@webcomponents/scoped-custom-element-registry";
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppComponent } from "./app.component";
@@ -19,6 +18,7 @@ import { Drawer } from "../components/drawer/drawer.component";
import { Dropdown } from "../components/dropdown/dropdown.component";
import { FileUpload } from "../components/fileupload/fileupload.component";
import { Footer } from "../components/footer/footer.component";
+import { Icon } from "../components/icon/icon.component";
import { Input } from "../components/input/input.component";
import { Mainnav } from "../components/mainnav/mainnav.component";
import { Masthead } from "../components/masthead/masthead.component";
@@ -56,6 +56,7 @@ import { Tooltip } from "../components/tooltip/tooltip.component";
FileUpload,
Footer,
Input,
+ Icon,
Mainnav,
Masthead,
Modal,
diff --git a/cypress/apps/angular-app/src/components/icon/icon.component.html b/cypress/apps/angular-app/src/components/icon/icon.component.html
new file mode 100644
index 00000000..f765a588
--- /dev/null
+++ b/cypress/apps/angular-app/src/components/icon/icon.component.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/cypress/apps/angular-app/src/components/icon/icon.component.ts b/cypress/apps/angular-app/src/components/icon/icon.component.ts
new file mode 100644
index 00000000..e4623e95
--- /dev/null
+++ b/cypress/apps/angular-app/src/components/icon/icon.component.ts
@@ -0,0 +1,7 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "icon-component",
+ templateUrl: "./icon.component.html"
+})
+export class Icon {}
diff --git a/cypress/apps/next-app/src/app/components/Breadcrumb.tsx b/cypress/apps/next-app/src/app/components/Breadcrumb.tsx
index 624ab92d..b04f65cf 100644
--- a/cypress/apps/next-app/src/app/components/Breadcrumb.tsx
+++ b/cypress/apps/next-app/src/app/components/Breadcrumb.tsx
@@ -4,10 +4,14 @@ import SgdsBreadcrumbItem from "@govtechsg/sgds-web-component/react/breadcrumb-i
export const Breadcrumb = () => {
return (
- Home
- Item 1
- Item 2
- Item 3
+
+ first
+
+ first
+ first
+ first
+ first
+ first
Last Item
)
diff --git a/index.html b/index.html
index 2bd9eb0e..8653a36b 100644
--- a/index.html
+++ b/index.html
@@ -1559,6 +1559,21 @@
Table w/ RemovableSort
Overflow
+
+ Option label
+ Option label
+ Google
+ Option label
+ Option label
+ Option label
+
+
diff --git a/src/components/Breadcrumb/sgds-breadcrumb.ts b/src/components/Breadcrumb/sgds-breadcrumb.ts
index e9554cdf..e5d9b330 100644
--- a/src/components/Breadcrumb/sgds-breadcrumb.ts
+++ b/src/components/Breadcrumb/sgds-breadcrumb.ts
@@ -2,7 +2,7 @@ import { property, query } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { html } from "lit/static-html.js";
import SgdsElement from "../../base/sgds-element";
-import { warnUnregisteredElements } from "../../utils/ce-registry";
+import SgdsOverflowMenu from "../../internals/OverflowMenu/sgds-overflow-menu";
import breadcrumbStyle from "./breadcrumb.css";
import type SgdsBreadcrumbItem from "./sgds-breadcrumb-item";
/**
@@ -13,53 +13,39 @@ import type SgdsBreadcrumbItem from "./sgds-breadcrumb-item";
*/
export class SgdsBreadcrumb extends SgdsElement {
static styles = [...SgdsElement.styles, breadcrumbStyle];
+ static dependencies = {
+ "sgds-overflow-menu": SgdsOverflowMenu
+ };
/** The aria-label of nav element within breadcrumb component. */
@property({ type: String }) ariaLabel = "breadcrumb";
/**@internal */
@query("slot") defaultSlot: HTMLSlotElement;
-
- private _checkDependencies() {
- warnUnregisteredElements("sgds-dropdown");
- warnUnregisteredElements("sgds-icon-button");
- warnUnregisteredElements("sgds-icon");
- }
/**
* creates `
- *
- *
- *
- *
+ *
*
* ...
- *
+ *
* `
*/
private _replaceExcessItemsWithDropdown(items: SgdsBreadcrumbItem[]) {
const breadcrumbItem = document.createElement("sgds-breadcrumb-item");
- const dropdown = document.createElement("sgds-dropdown");
- const overflowButton = document.createElement("sgds-icon-button");
- const icon = document.createElement("sgds-icon");
- icon.setAttribute("name", "three-dots");
- overflowButton.setAttribute("slot", "toggler");
- overflowButton.setAttribute("variant", "ghost");
- overflowButton.setAttribute("role", "button");
- overflowButton.setAttribute("aria-haspopup", "menu");
- overflowButton.appendChild(icon);
- dropdown.appendChild(overflowButton);
+ const overflowMenu = document.createElement("sgds-overflow-menu");
+ overflowMenu.setAttribute("aria-haspopup", "menu");
const mapItems = items.filter((item, index) => {
if (index > 0 && index < items.length - 2) {
const clonedAnchor = item.querySelector("a");
const clonedAnchorNode = clonedAnchor.cloneNode(true);
const dropdownItem = document.createElement("sgds-dropdown-item");
dropdownItem.appendChild(clonedAnchorNode);
- dropdown.appendChild(dropdownItem);
+ overflowMenu.appendChild(dropdownItem);
return;
} else {
return item;
}
});
- breadcrumbItem.appendChild(dropdown);
+ breadcrumbItem.appendChild(overflowMenu);
mapItems.splice(1, 0, breadcrumbItem);
this.defaultSlot.replaceWith(...mapItems);
@@ -78,7 +64,6 @@ export class SgdsBreadcrumb extends SgdsElement {
});
if (items.length >= 5) {
- this._checkDependencies();
this._replaceExcessItemsWithDropdown(items);
}
}
diff --git a/src/internals/OverflowMenu/index.ts b/src/internals/OverflowMenu/index.ts
new file mode 100644
index 00000000..7d5b1e4b
--- /dev/null
+++ b/src/internals/OverflowMenu/index.ts
@@ -0,0 +1,10 @@
+import { SgdsOverflowMenu } from "./sgds-overflow-menu";
+import { register } from "../../utils/ce-registry";
+
+register("sgds-overflow-menu", SgdsOverflowMenu);
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "sgds-overflow-menu": SgdsOverflowMenu;
+ }
+}
diff --git a/src/internals/OverflowMenu/overflow-menu.css b/src/internals/OverflowMenu/overflow-menu.css
new file mode 100644
index 00000000..ecd2be37
--- /dev/null
+++ b/src/internals/OverflowMenu/overflow-menu.css
@@ -0,0 +1,23 @@
+.overflow-btn {
+ width: var(--sgds-dimension-32);
+ height: var(--sgds-dimension-32);
+ background-color: var(--sgds-default-bg-transparent);
+ border-radius: var(--sgds-border-radius-sm);
+ border: 0;
+ padding: 0;
+ position: relative;
+ cursor: pointer;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+.overflow-btn:hover {
+ background-color: var(--sgds-default-bg-translucent);
+ }
+
+.overflow-btn:focus,
+.overflow-btn:focus-visible {
+ outline: 0;
+ box-shadow: var(--sgds-box-shadow-focus);
+ background-color: var(--sgds-default-bg-translucent);
+}
\ No newline at end of file
diff --git a/src/internals/OverflowMenu/sgds-overflow-menu.ts b/src/internals/OverflowMenu/sgds-overflow-menu.ts
new file mode 100644
index 00000000..2cec47be
--- /dev/null
+++ b/src/internals/OverflowMenu/sgds-overflow-menu.ts
@@ -0,0 +1,34 @@
+import { html } from "lit";
+import SgdsElement from "../../base/sgds-element";
+import overflowMenuStyles from "./overflow-menu.css";
+import { property } from "lit/decorators.js";
+import { SgdsDropdown } from "../../components/Dropdown/sgds-dropdown";
+import { SgdsDropdownItem } from "../../components/Dropdown/sgds-dropdown-item";
+import { SgdsIcon } from "../../components/Icon/sgds-icon";
+/**
+ * @summary An overflow menu is a UI element, often represented by three dots (⋮ or …), that opens a menu with additional actions or options.
+ * @slot default - The overflow menu items. Pass in sgds-dropdown-items in this slot
+ */
+export class SgdsOverflowMenu extends SgdsElement {
+ static styles = [...SgdsElement.styles, overflowMenuStyles];
+ static dependencies = {
+ "sgds-dropdown": SgdsDropdown,
+ "sgds-dropdown-item": SgdsDropdownItem,
+ "sgds-icon": SgdsIcon
+ };
+ /** Specifies a large or small button */
+ @property({ type: String, reflect: true }) size: "sm" | "md" = "md";
+
+ render() {
+ return html`
+
+
+
+
+ `;
+ }
+}
+
+export default SgdsOverflowMenu;
diff --git a/test/breadcrumb.test.ts b/test/breadcrumb.test.ts
index 7182f60e..3d7ccd09 100644
--- a/test/breadcrumb.test.ts
+++ b/test/breadcrumb.test.ts
@@ -63,22 +63,7 @@ describe("sgds-breadcrumb", () => {
size="md"
variant="primary"
>
-
-
-
-
-
+
{
Contacts
-
+
", () => {
+ it("semantically matches the DOM", async () => {
+ const el = await fixture(html``);
+ assert.shadowDom.equal(
+ el,
+ `
+
+
+
+
+ `
+ );
+ });
+});