diff --git a/src/components/sectionTitle/section-title.css b/src/components/sectionTitle/section-title.css new file mode 100644 index 0000000..dcdda05 --- /dev/null +++ b/src/components/sectionTitle/section-title.css @@ -0,0 +1,45 @@ +:host { + display: block; +} + +.container { + display: flex; + justify-content: space-between; + align-items: center; + gap: 16px; +} + +.main { + display: flex; + align-items: center; + gap: 16px; +} + +.heading { + display: flex; + align-items: center; + gap: 8px; +} + +.text-links { + display: flex; + flex-shrink: 0; + align-items: center; + gap: 16px; +} + +.buttons { + display: flex; + flex-shrink: 0; + align-items: center; + gap: 8px; +} + +h2 { + margin-block: 3px; + padding-inline-start: 8px; + font-size: 14px; + font-weight: bold; + line-height: 1.6; + position: relative; +} diff --git a/src/components/sectionTitle/sp-section-title.ts b/src/components/sectionTitle/sp-section-title.ts new file mode 100644 index 0000000..800b47b --- /dev/null +++ b/src/components/sectionTitle/sp-section-title.ts @@ -0,0 +1,97 @@ +// @ts-ignore +import resetStyle from "@acab/reset.css?inline" assert { type: "css" }; +// @ts-ignore +import foundationStyle from "../foundation.css?inline" assert { type: "css" }; +// @ts-ignore +import sectionTitleStyle from "./section-title.css?inline" assert { type: "css" }; + +const styles = new CSSStyleSheet(); +styles.replaceSync(`${resetStyle} ${foundationStyle} ${sectionTitleStyle}`); + +export class SpSectionTitle extends HTMLElement { + #headingElement = document.createElement("h2"); + #textLinkSlotElement = document.createElement("slot"); + #buttonSlotElement = document.createElement("slot"); + + set text(value: string) { + this.#headingElement.textContent = value; + } + + static get observedAttributes() { + return ["text"]; + } + + constructor() { + super(); + this.attachShadow({ mode: "open" }); + + this.shadowRoot!.adoptedStyleSheets = [styles]; + + this.#textLinkSlotElement.name = "text-links"; + this.#buttonSlotElement.name = "buttons"; + } + + connectedCallback() { + this.shadowRoot!.appendChild(this.#createContainer()); + + if (this.#textLinkSlotElement.assignedElements().length === 0) { + this.shadowRoot!.querySelector(".text-links")?.remove(); + } + + if (this.#buttonSlotElement.assignedElements().length === 0) { + this.shadowRoot!.querySelector(".buttons")?.remove(); + } + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + if (name === "text" && oldValue !== newValue) { + this.text = newValue; + } + } + + #createContainer() { + const container = document.createElement("div"); + container.classList.add("container"); + container.appendChild(this.#createMain()); + container.appendChild(this.#createButtons()); + return container; + } + + #createMain() { + const main = document.createElement("div"); + main.classList.add("main"); + main.appendChild(this.#createHeadingBlock()); + main.appendChild(this.#createTextLinks()); + return main; + } + + #createHeadingBlock() { + const div = document.createElement("div"); + div.classList.add("heading"); + div.appendChild(this.#headingElement); + return div; + } + + #createTextLinks() { + const div = document.createElement("div"); + div.classList.add("text-links"); + div.appendChild(this.#textLinkSlotElement); + return div; + } + + #createButtons() { + const div = document.createElement("div"); + div.classList.add("buttons"); + div.appendChild(this.#buttonSlotElement); + return div; + } +} + +declare global { + interface HTMLElementTagNameMap { + "sp-section-title": SpSectionTitle; + } +} + +customElements.get("sp-section-title") || + customElements.define("sp-section-title", SpSectionTitle); diff --git a/stories/sectionTitle/sp-section-title.story.ts b/stories/sectionTitle/sp-section-title.story.ts new file mode 100644 index 0000000..044dd7b --- /dev/null +++ b/stories/sectionTitle/sp-section-title.story.ts @@ -0,0 +1,69 @@ +import "../../src/components/sectionTitle/sp-section-title"; +import "../../src/components/button/sp-button"; +import "@sp-design/token/lib/speeda-tokens.css"; +import { Meta, StoryObj } from "@storybook/web-components"; +import { html } from "lit"; + +const meta: Meta = { + component: "sp-section-title", + argTypes: { + text: { type: "string" }, + }, + args: { + text: "Section Title", + }, +}; +export default meta; + +type Story = StoryObj; + +export const Basic: Story = {}; + +export const WithTextLinks: Story = { + render: (args) => html` + + TextLink1 + TextLink2 + + `, +}; + +export const WithButtons: Story = { + render: (args) => html` + + + + + `, +}; + +export const WithFullContents: Story = { + render: (args) => html` + + TextLink1 + TextLink2 + + + + `, +};