Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add link as new web component #31676

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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';
chrisdholt marked this conversation as resolved.
Show resolved Hide resolved
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
Loading