Skip to content

Commit

Permalink
add anchor button as a new component to web components v3 (microsoft#…
Browse files Browse the repository at this point in the history
…27395)

* add anchor as a new component to support anchor-button scenario

* dont forget managing anchor disabled

* update naming to anchor button

* Update change/@fluentui-web-components-b7e6d7ad-6aac-4ccb-b7ee-97424d76f9a2.json
  • Loading branch information
chrisdholt authored and radium-v committed Apr 30, 2024
1 parent e4750c7 commit ad5ff5d
Show file tree
Hide file tree
Showing 11 changed files with 426 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "feat(anchor-button): add anchor button to web components",
"packageName": "@fluentui/web-components",
"email": "chhol@microsoft.com",
"dependentChangeType": "patch"
}
4 changes: 4 additions & 0 deletions packages/web-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
"types": "./dist/esm/accordion-item/define.d.ts",
"default": "./dist/esm/accordion-item/define.js"
},
"./anchor-button": {
"types": "./dist/esm/anchor-button/define.d.ts",
"default": "./dist/esm/anchor-button/define.js"
},
"./avatar": {
"types": "./dist/esm/avatar/define.d.ts",
"default": "./dist/esm/avatar/define.js"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { FluentDesignSystem } from '../fluent-design-system.js';
import { AnchorButton } from './anchor-button.js';
import { styles } from './anchor-button.styles.js';
import { template } from './anchor-button.template.js';

/**
* The Fluent Anchor Button Element. Implements {@link @microsoft/fast-foundation#Anchor },
* {@link @microsoft/fast-foundation#anchorTemplate}
*
* @public
* @remarks
* HTML Element: \<fluent-anchor-button\>
*/
export const definition = AnchorButton.compose({
name: `${FluentDesignSystem.prefix}-anchor-button`,
template,
styles,
shadowOptions: {
delegatesFocus: true,
},
});
40 changes: 40 additions & 0 deletions packages/web-components/src/anchor-button/anchor-button.options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { AnchorOptions, ValuesOf } from '@microsoft/fast-foundation';
import { ButtonAppearance, ButtonShape, ButtonSize } from '../button/button.options.js';

/**
* Anchor Button Appearance constants
* @public
*/
export const AnchorButtonAppearance = ButtonAppearance;

/**
* An Anchor Button can be secondary, primary, outline, subtle, transparent
* @public
*/
export type AnchorButtonAppearance = ValuesOf<typeof AnchorButtonAppearance>;

/**
* An Anchor Button can be square, circular or rounded.
* @public
*/
export const AnchorButtonShape = ButtonShape;

/**
* An Anchor Button can be square, circular or rounded
* @public
*/
export type AnchorButtonShape = ValuesOf<typeof AnchorButtonShape>;

/**
* An Anchor Button can be a size of small, medium or large.
* @public
*/
export const AnchorButtonSize = ButtonSize;

/**
* An Anchor Button can be on of several preset sizes.
* @public
*/
export type AnchorButtonSize = ValuesOf<typeof AnchorButtonSize>;

export { AnchorOptions as AnchorButtonOptions };
214 changes: 214 additions & 0 deletions packages/web-components/src/anchor-button/anchor-button.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import { html } from '@microsoft/fast-element';
import type { Args, Meta } from '@storybook/html';
import { renderComponent } from '../helpers.stories.js';
import type { AnchorButton as FluentAnchorButton } from './anchor-button.js';
import { AnchorButtonAppearance, AnchorButtonShape, AnchorButtonSize } from './anchor-button.options.js';
import './define.js';

type AnchorButtonStoryArgs = Args & FluentAnchorButton;
type AnchorButtonStoryMeta = Meta<AnchorButtonStoryArgs>;

const storyTemplate = html<AnchorButtonStoryArgs>`
<fluent-anchor-button
href="${x => x.href}"
appearance="${x => x.appearance}"
shape="${x => x.shape}"
size="${x => x.size}"
?disabled="${x => x.disabled}"
?disabled-focusable="${x => x.disabledFocusable}"
?icon-only="${x => x.iconOnly}"
>
${x => x.content}
</fluent-anchor-button>
`;

export default {
title: 'Components/Button/Anchor',
args: {
content: 'Anchor',
href: '#',
disabled: false,
disabledFocusable: false,
},
argTypes: {
appearance: {
options: Object.values(AnchorButtonAppearance),
control: {
type: 'select',
},
},
shape: {
options: Object.values(AnchorButtonShape),
control: {
type: 'select',
},
},
size: {
options: Object.values(AnchorButtonSize),
control: {
type: 'select',
},
},
disabled: {
control: 'boolean',
table: {
type: {
summary: 'Sets the disabled state of the component',
},
defaultValue: {
summary: 'false',
},
},
},
disabledFocusable: {
control: 'boolean',
table: {
type: {
summary: 'The component is disabled but still focusable',
},
defaultValue: {
summary: 'false',
},
},
},
href: {
control: 'text',
},
content: {
control: 'Anchor text',
},
},
} as AnchorButtonStoryMeta;

export const AnchorButton = renderComponent(storyTemplate).bind({});

export const Appearance = renderComponent(html<AnchorButtonStoryArgs>`
<fluent-anchor-button href="#">Default</fluent-anchor-button>
<fluent-anchor-button href="#" appearance="primary">Primary</fluent-anchor-button>
<fluent-anchor-button href="#" appearance="outline">Outline</fluent-anchor-button>
<fluent-anchor-button href="#" appearance="subtle">Subtle</fluent-anchor-button>
<fluent-anchor-button href="#" appearance="transparent">Transparent</fluent-anchor-button>
`);

export const Shape = renderComponent(html<AnchorButtonStoryArgs>`
<fluent-anchor-button href="#" shape="rounded">Rounded</fluent-anchor-button>
<fluent-anchor-button href="#" shape="circular">Circular</fluent-anchor-button>
<fluent-anchor-button href="#" shape="square">Square</fluent-anchor-button>
`);

export const Size = renderComponent(html<AnchorButtonStoryArgs>`
<fluent-anchor-button href="#" size="small">Small</fluent-anchor-button>
<fluent-anchor-button href="#" size="small" icon
><svg
fill="currentColor"
slot="start"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
>Small with calendar icon</fluent-anchor-button
>
<fluent-anchor-button href="#" size="small" icon-only aria-label="Small icon only button"
><svg
fill="currentColor"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
></fluent-anchor-button>
<fluent-anchor-button href="#" size="medium">Medium</fluent-anchor-button>
<fluent-anchor-button href="#" size="medium" icon
><svg
fill="currentColor"
slot="start"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
>Medium with calendar icon</fluent-anchor-button
>
<fluent-anchor-button href="#" size="medium" icon-only aria-label="Medium icon only button"
><svg
fill="currentColor"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
></fluent-anchor-button>
<fluent-anchor-button href="#" size="large">Large</fluent-anchor-button>
<fluent-anchor-button href="#" size="large" icon
><svg
fill="currentColor"
slot="start"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
>Large with calendar icon</fluent-anchor-button
>
<fluent-anchor-button href="#" size="large" icon-only aria-label="Large icon only button"
><svg
fill="currentColor"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
></fluent-anchor-button>
`);

export const Disabled = renderComponent(html<AnchorButtonStoryArgs>`
<fluent-anchor-button href="#">Enabled state</fluent-anchor-button>
<fluent-anchor-button href="#" disabled>Disabled state</fluent-anchor-button>
<fluent-anchor-button href="#" disabled-focusable>Disabled focusable state</fluent-anchor-button>
<fluent-anchor-button href="#" appearance="primary">Enabled state</fluent-anchor-button>
<fluent-anchor-button href="#" appearance="primary" disabled>Disabled state</fluent-anchor-button>
<fluent-anchor-button href="#" appearance="primary" disabled-focusable>Disabled focusable state</fluent-anchor-button>
`);

export const WithLongText = renderComponent(html<AnchorButtonStoryArgs>`
<style>
.max-width {
width: 280px;
}
</style>
<fluent-anchor-button href="#">Short text</fluent-anchor-button>
<fluent-anchor-button href="#" class="max-width"
>Long text wraps after it hits the max width of the component</fluent-anchor-button
>
`);
11 changes: 11 additions & 0 deletions packages/web-components/src/anchor-button/anchor-button.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { css } from '@microsoft/fast-element';
import { styles as ButtonStyles } from '../button/button.styles.js';

// Need to support icon hover styles
export const styles = css`
${ButtonStyles}
.content {
text-align: center;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ElementViewTemplate } from '@microsoft/fast-element';
import { anchorTemplate } from '@microsoft/fast-foundation';
import type { AnchorButton } from './anchor-button.js';

/**
* The template for the Button component.
* @public
*/
export const template: ElementViewTemplate<AnchorButton> = anchorTemplate();
Loading

0 comments on commit ad5ff5d

Please sign in to comment.