Skip to content

Commit

Permalink
feat(text-link): text-link package
Browse files Browse the repository at this point in the history
  • Loading branch information
Powerplex committed Sep 13, 2023
1 parent 16126c6 commit 9ea534e
Show file tree
Hide file tree
Showing 10 changed files with 300 additions and 0 deletions.
25 changes: 25 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/components/text-link/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
src
**/*.stories.*
40 changes: 40 additions & 0 deletions packages/components/text-link/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "@spark-ui/text-link",
"version": "0.0.0",
"description": "TextLink is an accessible element for navigation.",
"publishConfig": {
"access": "public"
},
"keywords": [
"@spark-ui",
"react",
"component",
"accessible",
"accessibility",
"wai-aria",
"aria",
"a11y",
"link"
],
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"scripts": {
"build": "vite build"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0",
"tailwindcss": "^3.0.0"
},
"repository": {
"type": "git",
"url": "git@github.com:adevinta/spark.git",
"directory": "packages/components/text-link"
},
"bugs": {
"url": "https://github.com/adevinta/spark/issues"
},
"homepage": "https://sparkui.vercel.app",
"license": "MIT"
}
58 changes: 58 additions & 0 deletions packages/components/text-link/src/TextLink.doc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Meta, Canvas } from '@storybook/addon-docs'
import { ArgTypes } from '@storybook/blocks'

import { TextLink } from '.'

import * as stories from './TextLink.stories'

<Meta of={stories} />

# TextLink

TextLink is an accessible element for navigation.

## Install

```sh
npm install @spark-ui/text-link
```

## Import

```tsx
import { TextLink } from '@spark-ui/text-link'
```

## Props

This component support [all HTML attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attributes) supported by the `a` tag.

<ArgTypes of={TextLink} />

## Usage

### Default

<Canvas of={stories.Default} />

### Sizes

By default, the `TextLink` size adapts to the current font-size of your text.

Simply use `Tailwindcss` to set a difference size if necessary.

<Canvas of={stories.Sizes} />

### Intents

<Canvas of={stories.Intents} />

## Advanced Usage

### Icons

You can use Spark’s `Icon` component inside of the `TextLink` to display an icon.

This can be useful to showcase external links, download links, etc.

<Canvas of={stories.Icons} />
102 changes: 102 additions & 0 deletions packages/components/text-link/src/TextLink.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Icon } from '@spark-ui/icon'
import { Link as LinkSVG } from '@spark-ui/icons/dist/icons/Link'
import { Meta, StoryFn } from '@storybook/react'

import { TextLink, type TextLinkProps } from '.'

const meta: Meta<typeof TextLink> = {
title: 'Experimental/TextLink',
component: TextLink,
}

export default meta

export const Default: StoryFn = _args => {
return (
<p>
You should learn more about{' '}
<TextLink href="https://en.wikipedia.org/wiki/Kitten" target="_blank">
kitten
</TextLink>{' '}
and{' '}
<TextLink href="https://en.wikipedia.org/wiki/Puppy" target="_blank">
puppies
</TextLink>
.
</p>
)
}

export const Sizes: StoryFn = _args => {
return (
<div className="flex flex-col gap-md">
{['text-caption', 'text-body-1', 'text-headline-1'].map(textSize => {
return (
<p className={textSize}>
Have you head about{' '}
<TextLink href="/?path=/docs/getting-started--docs" target="_blank">
Spark
</TextLink>{' '}
? It’s awesome .
</p>
)
})}
<p className="text-body-1">
Have you head about{' '}
<TextLink
href="/?path=/docs/getting-started--docs"
target="_blank"
className="text-display-1"
>
Spark
</TextLink>{' '}
? It’s awesome .
</p>
</div>
)
}

const intents: TextLinkProps['intent'][] = [
'main',
'support',
'accent',
'basic',
'success',
'alert',
'danger',
'info',
'neutral',
]

export const Intents: StoryFn = _args => {
return (
<div className="flex flex-col gap-md">
{intents.map(intent => (
<p key={intent}>
{intent}{' '}
<TextLink intent={intent} href="https://en.wikipedia.org/wiki/Kitten" target="_blank">
link
</TextLink>
.
</p>
))}
</div>
)
}

export const Icons: StoryFn = _args => {
return (
<div className="flex flex-col gap-md">
<p>
External{' '}
<TextLink href="https://en.wikipedia.org/wiki/Kitten" target="_blank">
link
<Icon>
<LinkSVG />
</Icon>
</TextLink>
.
</p>
</div>
)
}
21 changes: 21 additions & 0 deletions packages/components/text-link/src/TextLink.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { render, screen } from '@testing-library/react'
import { describe, expect, it } from 'vitest'

import { TextLink } from './TextLink'

const urls = {
kitten: 'https://en.wikipedia.org/wiki/Kitten',
}

describe('TextLink', () => {
it('should render', () => {
render(<TextLink href={urls.kitten}>Kitten</TextLink>)

const link = screen.getByRole('link', {
name: 'Kitten',
})

expect(link).toBeInTheDocument()
expect(link).toHaveAttribute('href', urls.kitten)
})
})
41 changes: 41 additions & 0 deletions packages/components/text-link/src/TextLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { cva, type VariantProps } from 'class-variance-authority'
import React, { forwardRef } from 'react'

export type TextLinkProps = React.HTMLProps<HTMLAnchorElement> & StylesProps

const textLinkStyles = cva(
[
'underline inline-flex gap-sm items-center font-bold',
'focus-visible:ring-2 focus-visible:ring-outline-high focus-visible:outline-none',
],
{
variants: {
intent: {
main: 'text-main hover:text-main-hovered',
support: 'text-support hover:text-support-hovered',
accent: 'text-accent hover:text-accent-hovered',
basic: 'text-basic hover:text-basic-hovered',
success: 'text-success hover:text-success-hovered',
alert: 'text-alert hover:text-alert-hovered',
danger: 'text-error hover:text-error-hovered',
info: 'text-info hover:text-info-hovered',
neutral: 'text-neutral hover:text-neutral-hovered',
},
},
defaultVariants: {
intent: 'basic',
},
}
)

export type StylesProps = VariantProps<typeof textLinkStyles>

export const TextLink = forwardRef<HTMLAnchorElement, TextLinkProps>(
({ children, className, intent = 'basic', ...props }, ref) => {
return (
<a className={textLinkStyles({ className, intent })} ref={ref} {...props}>
{children}
</a>
)
}
)
1 change: 1 addition & 0 deletions packages/components/text-link/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './TextLink'
4 changes: 4 additions & 0 deletions packages/components/text-link/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../../tsconfig.json",
"include": ["src/**/*", "../../../global.d.ts"]
}
6 changes: 6 additions & 0 deletions packages/components/text-link/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import path from 'path'
import { getComponentConfiguration } from '../../../config/index'

const { name } = require(path.resolve(__dirname, 'package.json'))

export default getComponentConfiguration(process.cwd(), name)

0 comments on commit 9ea534e

Please sign in to comment.