diff --git a/packages/adaptive-ui/docs/api-report.md b/packages/adaptive-ui/docs/api-report.md index 138ec202..d0db9fb1 100644 --- a/packages/adaptive-ui/docs/api-report.md +++ b/packages/adaptive-ui/docs/api-report.md @@ -13,6 +13,9 @@ import { DesignTokenResolver } from '@microsoft/fast-foundation'; import { ElementStyles } from '@microsoft/fast-element'; import { ValuesOf } from '@microsoft/fast-foundation'; +// @public +export function applyMixins(derivedCtor: any, ...baseCtors: any[]): void; + // @public export class BasePalette implements Palette { constructor(source: Color, swatches: ReadonlyArray); diff --git a/packages/adaptive-ui/src/apply-mixins.ts b/packages/adaptive-ui/src/apply-mixins.ts index 7ccf57c7..63dff1a0 100644 --- a/packages/adaptive-ui/src/apply-mixins.ts +++ b/packages/adaptive-ui/src/apply-mixins.ts @@ -3,7 +3,7 @@ import { AttributeConfiguration } from "@microsoft/fast-element"; /** * Apply mixins to a constructor. * Sourced from {@link https://www.typescriptlang.org/docs/handbook/mixins.html | TypeScript Documentation }. - * @internal + * @public */ export function applyMixins(derivedCtor: any, ...baseCtors: any[]) { const derivedAttributes = AttributeConfiguration.locate(derivedCtor); diff --git a/packages/adaptive-ui/src/index.ts b/packages/adaptive-ui/src/index.ts index 0f7d0af5..f7d99fa9 100644 --- a/packages/adaptive-ui/src/index.ts +++ b/packages/adaptive-ui/src/index.ts @@ -2,6 +2,7 @@ export * from "./color/index.js"; export * from "./density/index.js"; export * from "./elevation/index.js"; export * from "./modules/index.js"; +export * from "./apply-mixins.js"; export * from "./adaptive-design-tokens.js"; export * from "./recipes.js"; export * from "./token-helpers-color.js"; diff --git a/packages/adaptive-web-components/src/components/button/button.stories.ts b/packages/adaptive-web-components/src/components/button/button.stories.ts index 8ad4d1c5..a995c426 100644 --- a/packages/adaptive-web-components/src/components/button/button.stories.ts +++ b/packages/adaptive-web-components/src/components/button/button.stories.ts @@ -14,6 +14,7 @@ export const storyTemplate = html>` formmethod="${(x) => x.formmethod}" ?formnovalidate="${(x) => x.formnovalidate}" formtarget="${(x) => x.formtarget}" + id="${(x) => x.id}" name="${(x) => x.name}" type="${(x) => x.type}" value="${(x) => x.value}" @@ -64,6 +65,7 @@ export default { formmethod: { control: "text" }, formnovalidate: { control: "boolean" }, formtarget: { control: "text" }, + id: { control: "text" }, name: { control: "text" }, type: { control: "select", options: Object.values(ButtonType) }, value: { control: "text" }, @@ -100,4 +102,6 @@ ButtonIconOnly.args = { `, + id: "icon-button", + ariaLabel: "Vacation Mode", }; diff --git a/packages/adaptive-web-components/src/components/button/button.ts b/packages/adaptive-web-components/src/components/button/button.ts index c4ea71bc..99d5b21b 100644 --- a/packages/adaptive-web-components/src/components/button/button.ts +++ b/packages/adaptive-web-components/src/components/button/button.ts @@ -1,11 +1,13 @@ import { FASTButton } from "@microsoft/fast-foundation"; +import { applyMixins } from "@adaptive-web/adaptive-ui"; +import { TooltipProvider } from "../../utilities/tooltip-provider.js"; /** * The Adaptive version of Button. Extends {@link @microsoft/fast-foundation#FASTButton}. * * @public */ -export class AdaptiveButton extends FASTButton { +export class AdaptiveButton extends FASTButton implements TooltipProvider { /** * Applies 'icon-only' class when there is only an SVG in the default slot. */ @@ -14,6 +16,8 @@ export class AdaptiveButton extends FASTButton { if (slottedElements.length === 1 && slottedElements[0] instanceof SVGElement) { this.control.classList.add("icon-only"); + + this.provideTooltip(this); } else { this.control.classList.remove("icon-only"); } @@ -23,3 +27,12 @@ export class AdaptiveButton extends FASTButton { this.control.focus(options); } } + +/** + * Mark internal because exporting class and interface of the same name + * confuses API documenter. + * TODO: https://github.com/microsoft/fast/issues/3317 + * @internal + */ +export interface AdaptiveButton extends TooltipProvider {} +applyMixins(FASTButton, TooltipProvider); diff --git a/packages/adaptive-web-components/src/components/tooltip/tooltip.styles.ts b/packages/adaptive-web-components/src/components/tooltip/tooltip.styles.ts index b74679bc..c0da5234 100644 --- a/packages/adaptive-web-components/src/components/tooltip/tooltip.styles.ts +++ b/packages/adaptive-web-components/src/components/tooltip/tooltip.styles.ts @@ -6,10 +6,11 @@ import { css, ElementStyles } from "@microsoft/fast-element"; */ export const templateStyles: ElementStyles = css` :host { + position: fixed; + visibility: hidden; height: fit-content; width: fit-content; white-space: nowrap; - visibility: hidden; } :host([visible]) { diff --git a/packages/adaptive-web-components/src/utilities/tooltip-provider.ts b/packages/adaptive-web-components/src/utilities/tooltip-provider.ts new file mode 100644 index 00000000..df52205e --- /dev/null +++ b/packages/adaptive-web-components/src/utilities/tooltip-provider.ts @@ -0,0 +1,16 @@ +import { FASTTooltip, tagFor } from "@microsoft/fast-foundation"; +import { uniqueId } from "@microsoft/fast-web-utilities"; + +export class TooltipProvider { + public provideTooltip(element: HTMLElement) { + if (element.ariaLabel) { + if (!element.id) { + element.id = uniqueId("tooltipAnchor"); + } + const tooltip = document.createElement(tagFor(FASTTooltip)) as FASTTooltip; + tooltip.innerText = element.ariaLabel; + tooltip.anchor = element.id; + element.parentNode?.insertBefore(tooltip, element); + } + } +}