Skip to content

Commit

Permalink
feat: add link as new web component (#31676)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisdholt authored Jun 12, 2024
1 parent e56dc8d commit a958850
Show file tree
Hide file tree
Showing 17 changed files with 518 additions and 94 deletions.
53 changes: 53 additions & 0 deletions apps/vr-tests-web-components/src/stories/link/link.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import * as React from 'react';
import { default as parse } from 'html-react-parser';
import { Steps, StoryWright } from 'storywright';
import { LinkDefinition, FluentDesignSystem } from '@fluentui/web-components';

LinkDefinition.define(FluentDesignSystem.registry);

const linkId = 'link-id';

const steps = new Steps()
.snapshot('default', { cropTo: '.testWrapper' })
.hover(`#${linkId}`)
.snapshot('hover', { cropTo: '.testWrapper' })
.mouseDown(`#${linkId}`)
.snapshot('pressed', { cropTo: '.testWrapper' })
.end();

export default {
title: 'Link',
decorators: [
(story: () => React.ReactElement) => {
return (
<StoryWright steps={steps}>
<div className="testWrapper" style={{ width: '300px' }}>
{story()}
</div>
</StoryWright>
);
},
],
};

export const Default = () => parse(`<fluent-link id="${linkId}">Default</fluent-link>`);

export const Subtle = () => parse(`<fluent-link id="${linkId}" appearance="subtle">Primary</fluent-link>`);

export const Inline = () =>
parse(`<p>This is an <fluent-link id="${linkId}" inline>inline link</fluent-link> used alongside text</p>.`);

export const WithLongText = () =>
parse(`
<style>
.max-width {
display: block;
width: 250px;
}
</style>
<p class="max-width">
This paragraph contains a link which is very long.
<fluent-link href="#">Fluent links wrap correctly between lines when they are very long.</fluent-link> This is
because they are inline elements.
</p>
`);
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "add link as a new web component",
"packageName": "@fluentui/web-components",
"email": "13071055+chrisdholt@users.noreply.github.com",
"dependentChangeType": "patch"
}
82 changes: 43 additions & 39 deletions packages/web-components/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,41 +126,20 @@ export const accordionStyles: ElementStyles;
export const accordionTemplate: ElementViewTemplate<Accordion>;

// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag
// Warning: (ae-forgotten-export) The symbol "BaseAnchor" needs to be exported by the entry point index.d.ts
// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "AnchorButton" because one of its declarations is marked as @internal
// Warning: (ae-missing-release-tag) "AnchorButton" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
export class AnchorButton extends FASTElement {
// @public (undocumented)
export class AnchorButton extends BaseAnchor {
appearance?: AnchorButtonAppearance | undefined;
// (undocumented)
connectedCallback(): void;
control: HTMLAnchorElement;
// @internal
defaultSlottedContent: HTMLElement[];
disabled?: boolean;
// (undocumented)
protected disabledChanged(prev: boolean, next: boolean): void;
disabledFocusable?: boolean;
// (undocumented)
protected disabledFocusableChanged(prev: boolean, next: boolean): void;
// (undocumented)
disconnectedCallback(): void;
download: string;
href: string;
hreflang: string;
iconOnly: boolean;
ping: string;
referrerpolicy: string;
rel: string;
shape?: AnchorButtonShape | undefined;
size?: AnchorButtonSize;
target: AnchorTarget;
type: string;
}

// Warning: (ae-forgotten-export) The symbol "DelegatesARIALink" needs to be exported by the entry point index.d.ts
//
// @internal
export interface AnchorButton extends StartEnd, DelegatesARIALink {
export interface AnchorButton extends StartEnd {
}

// @public
Expand All @@ -178,9 +157,6 @@ export type AnchorButtonAppearance = ValuesOf<typeof AnchorButtonAppearance>;
// @public (undocumented)
export const AnchorButtonDefinition: FASTElementDefinition<typeof AnchorButton>;

// @public
export type AnchorButtonOptions = StartEndOptions<AnchorButton>;

// @public
export const AnchorButtonShape: {
readonly circular: "circular";
Expand Down Expand Up @@ -2212,6 +2188,37 @@ export const lineHeightHero800 = "var(--lineHeightHero800)";
// @public
export const lineHeightHero900 = "var(--lineHeightHero900)";

// @public
export class Link extends BaseAnchor {
appearance?: LinkAppearance | undefined;
inline?: boolean;
}

// @public
export const LinkAppearance: {
readonly subtle: "subtle";
};

// @public
export type LinkAppearance = ValuesOf<typeof LinkAppearance>;

// @public (undocumented)
export const LinkDefinition: FASTElementDefinition<typeof Link>;

// @public
export const LinkTarget: {
readonly _self: "_self";
readonly _blank: "_blank";
readonly _parent: "_parent";
readonly _top: "_top";
};

// @public
export type LinkTarget = ValuesOf<typeof AnchorTarget>;

// @public
export const LinkTemplate: ElementViewTemplate<Link>;

// @public
export abstract class MatchMediaBehavior implements HostBehavior {
constructor(query: MediaQueryList);
Expand Down Expand Up @@ -2439,27 +2446,24 @@ export const MenuTemplate: ElementViewTemplate<Menu>;
// @public
export class ProgressBar extends FASTElement {
constructor();
// (undocumented)
connectedCallback(): void;
// @internal
elementInternals: ElementInternals;
// @internal
max?: number;
// (undocumented)
protected maxChanged(): void;
// @internal
protected maxChanged(prev: number | undefined, next: number | undefined): void;
// @internal
min?: number;
// (undocumented)
protected minChanged(): void;
protected minChanged(prev: number | undefined, next: number | undefined): void;
// @internal
percentComplete: number;
get percentComplete(): number;
shape?: ProgressBarShape;
thickness?: ProgressBarThickness;
validationState: ProgressBarValidationState | null;
// @internal
value?: number | null;
// (undocumented)
protected valueChanged(): void;
value?: number;
// @internal
protected valueChanged(prev: number | undefined, next: number | undefined): void;
}

// @public
Expand Down
5 changes: 5 additions & 0 deletions packages/web-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@
"types": "./dist/dts/label/define.d.ts",
"default": "./dist/esm/label/define.js"
},
"./link.js": {
"types": "./dist/dts/link/define.d.ts",
"default": "./dist/esm/link/define.js"
},
"./menu.js": {
"types": "./dist/dts/menu/define.d.ts",
"default": "./dist/esm/menu/define.js"
Expand Down Expand Up @@ -171,6 +175,7 @@
"./dist/esm/divider/define.js",
"./dist/esm/image/define.js",
"./dist/esm/label/define.js",
"./dist/esm/link/define.js",
"./dist/esm/menu/define.js",
"./dist/esm/menu-list/define.js",
"./dist/esm/menu-button/define.js",
Expand Down
92 changes: 47 additions & 45 deletions packages/web-components/src/anchor-button/anchor-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export type AnchorOptions = StartEndOptions<AnchorButton>;
*
* @public
*/
export class AnchorButton extends FASTElement {
export class BaseAnchor extends FASTElement {
/**
* The internal {@link https://developer.mozilla.org/docs/Web/API/ElementInternals | `ElementInternals`} instance for the component.
*
Expand Down Expand Up @@ -132,46 +132,6 @@ export class AnchorButton extends FASTElement {
@attr
public type?: string;

/**
* The appearance the anchor button should have.
*
* @public
* @remarks
* HTML Attribute: `appearance`
*/
@attr
public appearance?: AnchorButtonAppearance | undefined;

/**
* The shape the anchor button should have.
*
* @public
* @remarks
* HTML Attribute: `shape`
*/
@attr
public shape?: AnchorButtonShape | undefined;

/**
* The size the anchor button should have.
*
* @public
* @remarks
* HTML Attribute: `size`
*/
@attr
public size?: AnchorButtonSize;

/**
* The anchor button has an icon only, no text content
*
* @public
* @remarks
* HTML Attribute: `icon-only`
*/
@attr({ attribute: 'icon-only', mode: 'boolean' })
public iconOnly: boolean = false;

constructor() {
super();

Expand All @@ -198,8 +158,8 @@ export class AnchorButton extends FASTElement {
/**
* Handles changes to observable properties
* @internal
* @param source
* @param propertyName
* @param source - the source of the change
* @param propertyName - the property name being changed
*/
public handleChange(source: any, propertyName: string) {
if (propertyName in AnchorAttributes) {
Expand Down Expand Up @@ -241,8 +201,8 @@ export class AnchorButton extends FASTElement {
/**
* A method for updating proxy attributes when attributes have changed
* @internal
* @param attribute
* @param value
* @param attribute - an attribute to set/remove
* @param value - the value of the attribute
*/
private handleProxyAttributeChange(attribute: string, value: string | undefined): void {
if (value) {
Expand All @@ -259,6 +219,48 @@ export class AnchorButton extends FASTElement {
}
}

export class AnchorButton extends BaseAnchor {
/**
* The appearance the anchor button should have.
*
* @public
* @remarks
* HTML Attribute: `appearance`
*/
@attr
public appearance?: AnchorButtonAppearance | undefined;

/**
* The shape the anchor button should have.
*
* @public
* @remarks
* HTML Attribute: `shape`
*/
@attr
public shape?: AnchorButtonShape | undefined;

/**
* The size the anchor button should have.
*
* @public
* @remarks
* HTML Attribute: `size`
*/
@attr
public size?: AnchorButtonSize;

/**
* The anchor button has an icon only, no text content
*
* @public
* @remarks
* HTML Attribute: `icon-only`
*/
@attr({ attribute: 'icon-only', mode: 'boolean' })
public iconOnly: boolean = false;
}

/**
* Mark internal because exporting class and interface of the same name
* confuses API documenter.
Expand Down
1 change: 1 addition & 0 deletions packages/web-components/src/index-rollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import './divider/define.js';
import './field/define.js';
import './image/define.js';
import './label/define.js';
import './link/define.js';
import './menu-button/define.js';
import './menu-item/define.js';
import './menu-list/define.js';
Expand Down
20 changes: 10 additions & 10 deletions packages/web-components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,7 @@ export {
accordionStyles,
accordionTemplate,
} from './accordion/index.js';
export {
AnchorButton,
AnchorButtonAppearance,
AnchorButtonDefinition,
AnchorButtonShape,
AnchorButtonSize,
AnchorButtonTemplate,
AnchorTarget,
} from './anchor-button/index.js';
export type { AnchorButtonOptions } from './anchor-button/index.js';
export { Link, LinkAppearance, LinkDefinition, LinkTemplate, LinkTarget } from './link/index.js';
export {
Avatar,
AvatarActive,
Expand Down Expand Up @@ -110,6 +101,15 @@ export type { SlottableInput } from './field/index.js';
export { FluentDesignSystem } from './fluent-design-system.js';
export { Image, ImageDefinition, ImageFit, ImageShape, ImageStyles, ImageTemplate } from './image/index.js';
export { Label, LabelDefinition, LabelSize, LabelStyles, LabelTemplate, LabelWeight } from './label/index.js';
export {
AnchorButton,
AnchorButtonAppearance,
AnchorButtonDefinition,
AnchorButtonShape,
AnchorButtonSize,
AnchorButtonTemplate,
AnchorTarget,
} from './anchor-button/index.js';
export {
MenuButton,
MenuButtonAppearance,
Expand Down
4 changes: 4 additions & 0 deletions packages/web-components/src/link/define.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { FluentDesignSystem } from '../fluent-design-system.js';
import { definition } from './link.definition.js';

definition.define(FluentDesignSystem.registry);
4 changes: 4 additions & 0 deletions packages/web-components/src/link/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { definition as LinkDefinition } from './link.definition.js';
export { Link } from './link.js';
export { LinkAppearance, LinkTarget } from './link.options.js';
export { template as LinkTemplate } from './link.template.js';
Loading

0 comments on commit a958850

Please sign in to comment.