diff --git a/src/ui/components/button.ts b/src/ui/components/button.ts new file mode 100644 index 0000000..a61b61e --- /dev/null +++ b/src/ui/components/button.ts @@ -0,0 +1,115 @@ +import { css, html, LitElement, type TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators.js"; +import { ifDefined } from "lit/directives/if-defined.js"; + +import { cls } from "../utils"; + +/** + * Element that offers a button, allowing a user to activate functionality. + */ +@customElement("sd-button") +export class SDButtonElement extends LitElement { + /** + * @inheritdoc + */ + public static styles = [ + super.styles ?? [], + css` + :host { + display: inline-flex; + } + + button { + align-items: center; + background: var(--color-surface); + border: none; + border-radius: var(--rounding-m); + color: var(--color-content-primary); + display: flex; + font-family: var(--typography-body-m-family); + font-size: var(--typography-body-m-size); + font-weight: var(--typography-body-m-weight); + height: var(--size-2xl); + justify-content: center; + line-height: var(--typography-body-m-line-height); + outline: none; + padding: 0 var(--space-s); + width: 100%; + + &:not(:disabled) { + &:hover { + cursor: pointer; + background: var(--color-surface-hover); + } + + &:active { + background: var(--color-surface-pressed); + } + + &.accent, + &.accent:hover, + &.accent:active { + background: var(--color-surface-accent); + color: var(--color-content-ondark); + } + + &.danger, + &.danger:hover, + &.danger:active { + background: var(--color-surface-negative); + color: var(--color-content-onlight); + } + } + + &:focus-visible { + box-shadow: var(--highlight-box-shadow); + outline: var(--highlight-outline--focus); + outline-offset: var(--highlight-outline-offset); + } + + &:disabled { + background: var(--color-surface-disabled); + color: var(--color-content-disabled); + } + } + `, + ]; + + /** + * Determines whether the button is disabled; default `false`. + */ + @property({ + reflect: true, + type: Boolean, + }) + public accessor disabled = false; + + /** + * Indicates the type of interaction the user will experience when clicking the button. + */ + @property() + public accessor variant: "accent" | "danger" | undefined = undefined; + + /** + * @inheritdoc + */ + public override render(): TemplateResult { + return html` + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + /** + * Element that offers a button, allowing a user to activate functionality. + */ + "sd-button": SDButtonElement; + } +} diff --git a/src/ui/components/divider.ts b/src/ui/components/divider.ts new file mode 100644 index 0000000..0e97217 --- /dev/null +++ b/src/ui/components/divider.ts @@ -0,0 +1,89 @@ +import { css, html, LitElement, type TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators.js"; + +/** + * Element that provides a horizontal divider, with an optional label. + */ +@customElement("sd-divider") +export class SDDividerElement extends LitElement { + /** + * @inheritdoc + */ + public static styles = [ + super.styles ?? [], + css` + .container { + display: grid; + align-items: center; + height: var(--size-xl); + margin: var(--size-2xs) 0; + } + + hr, + label { + grid-area: 1 / 1 / 2 / 2; /* Place everything on top of one another */ + } + + hr { + background-color: var(--color-border-subtle); + border: none; + height: 1px; + width: 100%; + } + + label { + align-items: center; + background: var(--color-page); + border: 1px solid var(--color-border-subtle); + border-radius: var(--rounding-full); + color: var(--color-content-secondary); + display: flex; + height: 100%; + justify-self: center; + overflow: hidden; + padding: 0 var(--space-xs); + max-width: 75%; + + /* Child element allows truncating text within flexbox */ + & span { + overflow: hidden; + text-overflow: ellipsis; + user-select: none; + white-space: nowrap; + } + } + `, + ]; + + /** + * Label to show within the divider. + */ + @property() + public accessor label: string | undefined; + + /** + * @inheritdoc + */ + public override render(): TemplateResult { + return html` +
+
+ ${this.label && + html` + + `} +
+ `; + } +} + +declare global { + interface HTMLElementTagNameMap { + /** + * Element that provides a horizontal divider, with an optional label. + */ + "sd-divider": SDDividerElement; + } +} diff --git a/src/ui/components/field.ts b/src/ui/components/field.ts index f043d04..1b8fb62 100644 --- a/src/ui/components/field.ts +++ b/src/ui/components/field.ts @@ -22,6 +22,7 @@ export class SDFieldElement extends LitElement { align-items: center; display: flex; height: var(--size-2xl); + width: 240px; } `, ]; diff --git a/src/ui/components/index.ts b/src/ui/components/index.ts index ed4f976..f86dd9d 100644 --- a/src/ui/components/index.ts +++ b/src/ui/components/index.ts @@ -1,3 +1,5 @@ +export * from "./button"; +export * from "./divider"; export * from "./field"; export * from "./label"; export * from "./option";