Skip to content

Commit

Permalink
feat: add heading storybook
Browse files Browse the repository at this point in the history
  • Loading branch information
driss-chelouati committed Sep 5, 2023
1 parent 853eac2 commit 9eb5e8d
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 6 deletions.
6 changes: 3 additions & 3 deletions .storybook/preview-head.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
background-color: transparent !important;
}

h2 {
h2:not(.nui-heading) {
color: #4c1d95 !important;
}

h3 {
h3:not(.nui-heading) {
font-weight: 500 !important;
font-size: 1.15rem !important;
}

h3 + p {
h3:not(.nui-heading) + p {
margin-top: 0.25rem !important;
color: #64748b !important;
}
Expand Down
29 changes: 29 additions & 0 deletions src/plugins/components/heading/heading.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { html, unsafeStatic } from 'lit/static-html.js'
import { spread } from '@open-wc/lit-helpers'

import type { HeadingAttrs } from './heading.types'
import * as variants from './heading.variants'

/**
* Primary UI component for user interaction
*/
export const Heading = ({
size = 'xl',
weight = 'semibold',
lead = 'normal',
as = 'p',
children,
...attrs
}: HeadingAttrs) => {
return html`
<${unsafeStatic(as)} class=${[
'nui-heading',
size && variants.size[size],
weight && variants.weight[weight],
lead && variants.lead[lead],
]
.filter(Boolean)
.join(' ')}
${spread(attrs)}>${children}</${unsafeStatic(as)}>
`
}
75 changes: 75 additions & 0 deletions src/plugins/components/heading/heading.doc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Meta, Primary, Controls, Story } from '@storybook/blocks'
import * as HeadingStories from './heading.stories'
import { defaultHeadingConfig } from '.'

<Meta of={HeadingStories} />

# Heading

Headings are an important part of any website or application and are often referred as part of the "Typography". They help creating structure and consistency accross the page and your content.

<Primary />

## Props

<Controls />

## Variants

<br />

### Sizes

Use the Heading component to display a title or an important heading. You can use various props to customize the size, weight, the line-height and the Html tag used to render the heading.

<div className="bg-slate-100 dark:bg-slate-900 p-6 rounded-sm">
<Story of={HeadingStories.SizeSm} />
<br />
<Story of={HeadingStories.SizeMd} />
<br />
<Story of={HeadingStories.SizeLg} />
<br />
<Story of={HeadingStories.SizeXl} />
<br />
<Story of={HeadingStories.Size2Xl} />
<br />
<Story of={HeadingStories.Size3Xl} />
</div>

<br />
<br />

## Customization

### Default config

<div class="relative">
<details class="relative bg-slate-50 border border-slate-200 rounded-lg p-4 [&>summary>svg]:open:-rotate-180">
<summary class="list-none cursor-pointer">
<span class="font-sans text-slate-500">View configuration options</span>
<svg
class="w-5 h-5 text-slate-500 absolute top-5 end-4 transition-transform duration-300"
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m6 9l6 6l6-6"
/>
</svg>
</summary>

<div class="!mt-4">
<pre >
{JSON.stringify(defaultHeadingConfig, null, 2)}
</pre>
</div>

</details>
</div>
155 changes: 155 additions & 0 deletions src/plugins/components/heading/heading.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import type { Meta, StoryObj } from '@storybook/web-components'
import { html } from 'lit'

import type { HeadingAttrs } from './heading.types'
import { Heading } from './heading.component'

// More on how to set up stories at: https://storybook.js.org/docs/web-components/writing-stories/introduction
const meta = {
title: 'Shuriken UI/Typography/Heading',
// tags: ['autodocs'],
render: (args) => Heading(args),
argTypes: {
as: {
control: { type: 'select' },
options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span', 'p'],
defaultValue: 'p',
},
size: {
control: { type: 'select' },
options: [
'xs',
'sm',
'md',
'lg',
'xl',
'2xl',
'3xl',
'4xl',
'5xl',
'6xl',
'7xl',
'8xl',
'9xl',
],
defaultValue: 'xl',
},
weight: {
control: { type: 'select' },
options: ['light', 'normal', 'medium', 'semibold', 'bold', 'extrabold'],
defaultValue: 'normal',
},
lead: {
control: { type: 'select' },
options: ['none', 'tight', 'snug', 'normal', 'relaxed', 'loose'],
defaultValue: 'normal',
},
},
} satisfies Meta<HeadingAttrs>

export default meta
type Story = StoryObj<HeadingAttrs>

// first export is the Primary story

// #region Main
export const Main: Story = {
name: 'Main example',
args: {
// set default values used for UI preview
as: 'h2',
size: 'xl',
weight: 'semibold',
lead: 'none',
children: html`
Hello world
`,
},
}
// #endregion

// #region Variants
export const SizeSm: Story = {
name: 'Size: sm',
args: {
// set default values used for UI preview
as: 'h2',
size: 'sm',
weight: 'medium',
lead: 'none',
children: html`
Iam a sm heading
`,
},
}

export const SizeMd: Story = {
name: 'Size: md',
args: {
// set default values used for UI preview
as: 'h2',
size: 'md',
weight: 'medium',
lead: 'none',
children: html`
Iam a md heading
`,
},
}

export const SizeLg: Story = {
name: 'Size: lg',
args: {
// set default values used for UI preview
as: 'h2',
size: 'lg',
weight: 'medium',
lead: 'none',
children: html`
Iam a lg heading
`,
},
}

export const SizeXl: Story = {
name: 'Size: xl',
args: {
// set default values used for UI preview
as: 'h2',
size: 'xl',
weight: 'medium',
lead: 'none',
children: html`
Iam a xl heading
`,
},
}

export const Size2Xl: Story = {
name: 'Size: 2xl',
args: {
// set default values used for UI preview
as: 'h2',
size: '2xl',
weight: 'medium',
lead: 'none',
children: html`
Iam a 2xl heading
`,
},
}

export const Size3Xl: Story = {
name: 'Size: 3xl',
args: {
// set default values used for UI preview
as: 'h2',
size: '3xl',
weight: 'medium',
lead: 'none',
children: html`
Iam a 3xl heading
`,
},
}
// #endregion
35 changes: 35 additions & 0 deletions src/plugins/components/heading/heading.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { axe } from 'vitest-axe'
import { expect, test, describe } from 'vitest'
import { render, html } from 'lit'

import { Heading } from './heading.component'

describe('Heading', () => {
test('Should render slot', () => {
const heading = Heading({
children: html`
<span>Hello world</span>
`,
})

render(heading, document.body)

expect(document.body.querySelector('.nui-heading')?.outerHTML)?.toContain(
'Hello world',
)
})

test('Should have no axe violations', async () => {
const heading = Heading({
children: html`
<span>Hello world</span>
`,
})

render(heading, document.body)

expect(
await axe(document.body.querySelector('.nui-heading')!.outerHTML),
)?.toHaveNoViolations()
})
})
30 changes: 30 additions & 0 deletions src/plugins/components/heading/heading.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { PropertyVariant } from '~/types/utils'

export interface HeadingProps extends Record<string, unknown> {
as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'span' | 'p'
size?:
| 'xs'
| 'sm'
| 'md'
| 'lg'
| 'xl'
| '2xl'
| '3xl'
| '4xl'
| '5xl'
| '6xl'
| '7xl'
| '8xl'
| '9xl'
weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold' | 'extrabold'
lead?: 'none' | 'tight' | 'snug' | 'normal' | 'relaxed' | 'loose'
}

export interface HeadingEvents {}

export interface HeadingSlots {
children: any
}

export type HeadingAttrs = HeadingProps & HeadingEvents & HeadingSlots
export type HeadingVariant<T> = PropertyVariant<T, HeadingProps>
35 changes: 35 additions & 0 deletions src/plugins/components/heading/heading.variants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { HeadingVariant } from './heading.types'

export const size = {
xs: 'nui-heading-xs',
sm: 'nui-heading-sm',
md: 'nui-heading-md',
lg: 'nui-heading-lg',
xl: 'nui-heading-xl',
'2xl': 'nui-heading-2xl',
'3xl': 'nui-heading-3xl',
'4xl': 'nui-heading-4xl',
'5xl': 'nui-heading-5xl',
'6xl': 'nui-heading-6xl',
'7xl': 'nui-heading-7xl',
'8xl': 'nui-heading-8xl',
'9xl': 'nui-heading-9xl',
} as const satisfies HeadingVariant<'size'>

export const weight = {
light: 'nui-weight-light',
normal: 'nui-weight-normal',
medium: 'nui-weight-medium',
semibold: 'nui-weight-semibold',
bold: 'nui-weight-bold',
extrabold: 'nui-weight-extrabold',
} as const satisfies HeadingVariant<'weight'>

export const lead = {
none: 'nui-lead-none',
tight: 'nui-lead-tight',
snug: 'nui-lead-snug',
normal: 'nui-lead-normal',
relaxed: 'nui-lead-relaxed',
loose: 'nui-lead-loose',
} as const satisfies HeadingVariant<'lead'>
Loading

0 comments on commit 9eb5e8d

Please sign in to comment.