Skip to content

Commit

Permalink
feat(link): add all anchor attrs, non-standalone links support slotte…
Browse files Browse the repository at this point in the history
…d icons
  • Loading branch information
Erbil Nas committed Dec 26, 2024
1 parent a6a08cc commit e5dc48e
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 164 deletions.
37 changes: 9 additions & 28 deletions src/components/link/bl-link.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,10 @@
/* States */
.link:hover {
text-decoration: none;
}

.link:hover:not(.disabled) {
color: var(--hover-color);
}

.link:active:not(.disabled) {
.link:active {
color: var(--active-color);
}

Expand All @@ -50,8 +47,8 @@
color: var(--bl-color-primary);
}

.link.standalone.kind-primary:hover:not(.disabled),
.link.standalone.kind-primary:active:not(.disabled) {
.link.standalone.kind-primary:hover,
.link.standalone.kind-primary:active {
color: var(--bl-color-primary-highlight);
}

Expand All @@ -60,8 +57,8 @@
color: var(--bl-color-neutral);
}

.link.standalone.kind-neutral:hover:not(.disabled),
.link.standalone.kind-neutral:active:not(.disabled) {
.link.standalone.kind-neutral:hover,
.link.standalone.kind-neutral:active {
color: var(--bl-color-neutral-highlight);
}

Expand All @@ -82,25 +79,9 @@
}

/* Icon styles */
.icon {
::slotted([slot="icon"]) {
margin-inline-start: var(--bl-size-3xs);
}

/* Disabled state */
.link.disabled {
opacity: 0.5;
cursor: not-allowed;
}

/* Screen reader only text */
.visually-hidden {
position: absolute;
block-size: 1px;
inline-size: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
margin-inline-end: var(--bl-size-3xs);
display: inline-block;
vertical-align: middle;
}
169 changes: 119 additions & 50 deletions src/components/link/bl-link.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@ import { centeredLayout } from "../../utilities/chromatic-decorators";


interface LinkArgs {
target?: string;
href?: string;
variant?: "inline" | "standalone";
size?: "small" | "medium" | "large";
kind?: "primary" | "neutral";
external?: boolean;
disabled?: boolean;
target?: HTMLAnchorElement["target"];
rel?: HTMLAnchorElement["rel"];
hreflang?: HTMLAnchorElement["hreflang"];
type?: HTMLAnchorElement["type"];
referrerPolicy?: HTMLAnchorElement["referrerPolicy"];
download?: HTMLAnchorElement["download"];
ping?: HTMLAnchorElement["ping"];
"aria-label"?: string;
content?: string;
customStyles?: string;
icon?: string;
}

const FIGMA_LINK = "https://www.figma.com/design/RrcLH0mWpIUy4vwuTlDeKN/Baklava-Design-Guide?node-id=23617-1414";
Expand All @@ -34,15 +40,17 @@ const meta: Meta<LinkArgs> = {
component:
"<div class=\"bl-docs-container\">" +
"<p class=\"bl-docs-description\">" +
"The Link component is used for navigation between pages or to external URLs." +
"The Link component is used for navigation between pages or to external URLs. " +
"It supports all native anchor tag attributes and provides additional styling variants. " +
"When not using the standalone variant, you can provide a custom icon using the icon slot." +
"</p>" +

"<div class=\"bl-docs-links\" style=\"display: flex; gap: var(--bl-size-2xs); margin-top: var(--bl-size-m);\">" +
"<bl-badge icon=\"document\" style=\"--bl-badge-background: var(--bl-color-surface-hover)\">" +
"<bl-link variant='inline' target='" + ADR_LINK + "' external>ADR</bl-link>" +
"<bl-link variant='inline' href='" + ADR_LINK + "' target='_blank'>ADR</bl-link>" +
"</bl-badge>" +
"<bl-badge icon=\"puzzle\" style=\"--bl-badge-background: var(--bl-color-surface-hover)\">" +
"<bl-link variant='inline' target='" + FIGMA_LINK + "' external>Figma</bl-link>" +
"<bl-link variant='inline' href='" + FIGMA_LINK + "' target='_blank'>Figma</bl-link>" +
"</bl-badge>" +
"</div>" +
"</div>",
Expand All @@ -53,9 +61,9 @@ const meta: Meta<LinkArgs> = {
centeredLayout,
],
argTypes: {
target: {
href: {
control: "text",
description: "Target URL for the link",
description: "URL that the hyperlink points to",
table: {
type: { summary: "string" },
},
Expand Down Expand Up @@ -87,20 +95,65 @@ const meta: Meta<LinkArgs> = {
defaultValue: { summary: "primary" },
},
},
external: {
control: "boolean",
description: "Whether the link is external",
target: {
control: { type: "select" },
options: ["_self", "_blank", "_parent", "_top"],
description: "Where to display the linked URL",
table: {
type: { summary: "HTMLAnchorElement['target']" },
defaultValue: { summary: "_self" },
},
},
rel: {
control: "text",
description: "Relationship between documents (e.g., noopener noreferrer)",
table: {
type: { summary: "HTMLAnchorElement['rel']" },
},
},
hreflang: {
control: "text",
description: "Language of the linked document",
table: {
type: { summary: "HTMLAnchorElement['hreflang']" },
},
},
type: {
control: "text",
description: "MIME type of the linked document",
table: {
type: { summary: "HTMLAnchorElement['type']" },
},
},
referrerPolicy: {
control: { type: "select" },
options: [
"no-referrer",
"no-referrer-when-downgrade",
"origin",
"origin-when-cross-origin",
"same-origin",
"strict-origin",
"strict-origin-when-cross-origin",
"unsafe-url",
],
description: "Referrer policy for the link",
table: {
type: { summary: "HTMLAnchorElement['referrerPolicy']" },
},
},
download: {
control: "text",
description: "Whether to download the resource instead of navigating to it",
table: {
type: { summary: "boolean" },
defaultValue: { summary: false },
type: { summary: "HTMLAnchorElement['download']" },
},
},
disabled: {
control: "boolean",
description: "Whether the link appears disabled (changes cursor to not-allowed)",
ping: {
control: "text",
description: "URLs to be notified when following the link",
table: {
type: { summary: "boolean" },
defaultValue: { summary: false },
type: { summary: "HTMLAnchorElement['ping']" },
},
},
"aria-label": {
Expand All @@ -110,6 +163,13 @@ const meta: Meta<LinkArgs> = {
type: { summary: "string" },
},
},
icon: {
control: "text",
description: "Icon name for custom icon (only applies to non-standalone variants)",
table: {
type: { summary: "string" },
},
},
},
};

Expand All @@ -119,30 +179,36 @@ type Story = StoryObj<LinkArgs>;

const LinkTemplate = (args: LinkArgs) => html`
<bl-link
target=${ifDefined(args.target)}
href=${ifDefined(args.href)}
variant=${ifDefined(args.variant)}
size=${ifDefined(args.size)}
kind=${ifDefined(args.kind)}
?external=${args.external}
?disabled=${args.disabled}
target=${ifDefined(args.target)}
rel=${ifDefined(args.rel)}
hreflang=${ifDefined(args.hreflang)}
type=${ifDefined(args.type)}
referrerpolicy=${ifDefined(args.referrerPolicy)}
download=${ifDefined(args.download)}
ping=${ifDefined(args.ping)}
aria-label=${ifDefined(args["aria-label"])}
style=${ifDefined(args.customStyles)}
>
${args.content || "Link Text"}
${args.icon ? html`<bl-icon name="${args.icon}" slot="icon"></bl-icon>` : ""}
</bl-link>
`;

export const Default: Story = {
args: {
target: "/",
href: "/",
content: "Link",
},
render: LinkTemplate,
};

export const InlineLink: Story = {
args: {
target: "/",
href: "/",
variant: "inline",
content: "Link",
},
Expand Down Expand Up @@ -176,65 +242,68 @@ export const InlineLink: Story = {

export const StandaloneLink: Story = {
args: {
target: "/",
href: "/",
variant: "standalone",
content: "Link",
},
render: LinkTemplate,
};

export const SizeVariants: Story = {
export const CustomIconLink: Story = {
args: {
variant: "standalone",
href: "/",
content: "Link with Custom Icon",
icon: "external_link",
},
render: () => html`
<div style="display: flex; gap: 16px; align-items: center;">
${LinkTemplate({ target: "/", variant: "standalone", size: "small", content: "Small" })}
${LinkTemplate({ target: "/", variant: "standalone", size: "medium", content: "Medium" })}
${LinkTemplate({ target: "/", variant: "standalone", size: "large", content: "Large" })}
</div>
`,
render: LinkTemplate,
};

export const KindVariants: Story = {
export const SizeVariants: Story = {
args: {
variant: "standalone",
},
render: () => html`
<div style="display: flex; gap: 16px; align-items: center;">
${LinkTemplate({ target: "/", variant: "standalone", kind: "primary", content: "Primary" })}
${LinkTemplate({ target: "/", variant: "standalone", kind: "neutral", content: "Neutral" })}
${LinkTemplate({ href: "/", variant: "standalone", size: "small", content: "Small" })}
${LinkTemplate({ href: "/", variant: "standalone", size: "medium", content: "Medium" })}
${LinkTemplate({ href: "/", variant: "standalone", size: "large", content: "Large" })}
</div>
`,
};

export const ExternalLinks: Story = {
export const KindVariants: Story = {
args: {
external: true,
variant: "standalone",
},
render: () => html`
<div style="display: flex; gap: 16px; align-items: center;">
${LinkTemplate({ target: "https://example.com", external: true, content: "External Link" })}
${LinkTemplate({ href: "/", variant: "standalone", kind: "primary", content: "Primary" })}
${LinkTemplate({ href: "/", variant: "standalone", kind: "neutral", content: "Neutral" })}
</div>
`,
};

export const DisabledLinks: Story = {
export const NativeAnchorAttributes: Story = {
args: {
disabled: true,
href: "https://example.com",
target: "_blank",
rel: "noopener noreferrer",
hreflang: "en",
type: "text/html",
referrerPolicy: "no-referrer",
download: "file.pdf",
ping: "https://analytics.example.com",
content: "External Link with Native Attributes",
},
render: () => html`
<div style="display: flex; gap: 16px; align-items: center;">
${LinkTemplate({ target: "/", disabled: true, content: "Disabled Link" })}
</div>
`,
render: LinkTemplate,
};

export const AccessibleLink: Story = {
args: {
target: "/",
href: "/",
"aria-label": "View your profile settings",
content: "Profile",

},
render: LinkTemplate,
};
Expand All @@ -243,17 +312,17 @@ export const CustomInlineColors: Story = {
render: () => html`
<div style="display: flex; gap: 16px; align-items: center;">
${LinkTemplate({
target: "/",
href: "/",
content: "Success Link",
customStyles: "--bl-link-color: var(--bl-color-success); --bl-link-hover-color: var(--bl-color-success-highlight); --bl-link-active-color: var(--bl-color-success-highlight);"
})}
${LinkTemplate({
target: "/",
href: "/",
content: "Warning Link",
customStyles: "--bl-link-color: var(--bl-color-warning); --bl-link-hover-color: var(--bl-color-warning-highlight); --bl-link-active-color: var(--bl-color-warning-highlight);"
})}
${LinkTemplate({
target: "/",
href: "/",
content: "Danger Link",
customStyles: "--bl-link-color: var(--bl-color-danger); --bl-link-hover-color: var(--bl-color-danger-highlight); --bl-link-active-color: var(--bl-color-danger-highlight);"
})}
Expand Down
Loading

0 comments on commit e5dc48e

Please sign in to comment.