-
Parent card
-
+
Parent card
Nested card
diff --git a/src/shared/primitives/Button/Button.stories.tsx b/src/shared/primitives/Button/Button.stories.tsx
index eef6c7f..8595b80 100644
--- a/src/shared/primitives/Button/Button.stories.tsx
+++ b/src/shared/primitives/Button/Button.stories.tsx
@@ -123,3 +123,22 @@ export const FullWidth: Story = {
fullWidth: true,
},
}
+export const Focused: Story = {
+ args: {
+ children: 'Focused Button',
+ },
+
+ play: async ({ canvasElement }) => {
+ const button = canvasElement.querySelector('button')
+
+ button?.focus()
+ },
+}
+
+export const IconOnly: Story = {
+ args: {
+ 'aria-label': 'Close',
+
+ children: '×',
+ },
+}
diff --git a/src/shared/primitives/Input/Input.stories.tsx b/src/shared/primitives/Input/Input.stories.tsx
index d1bc2b8..7330393 100644
--- a/src/shared/primitives/Input/Input.stories.tsx
+++ b/src/shared/primitives/Input/Input.stories.tsx
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react-vite'
import { useState } from 'react'
-import { MagnifyingGlassIcon, EyeIcon } from '@heroicons/react/24/outline'
+import { MagnifyingGlassIcon, XMarkIcon } from '@heroicons/react/24/outline'
import { Input, type InputProps } from './Input'
@@ -81,7 +81,7 @@ export const WithIcons: Story = {
prefixIcon:
,
- suffixIcon:
,
+ suffixIcon:
,
},
}
@@ -112,3 +112,15 @@ export const Focus: Story = {
input?.focus()
},
}
+
+export const ReadOnly: Story = {
+ render: (args) =>
,
+
+ args: {
+ label: 'Read only',
+
+ value: 'Readonly value',
+
+ isReadOnly: true,
+ },
+}
diff --git a/src/shared/primitives/Progressbar/ProgressBar.stories.tsx b/src/shared/primitives/Progressbar/ProgressBar.stories.tsx
index 4e87743..1837d23 100644
--- a/src/shared/primitives/Progressbar/ProgressBar.stories.tsx
+++ b/src/shared/primitives/Progressbar/ProgressBar.stories.tsx
@@ -80,3 +80,13 @@ export const ExtraSmall: Story = {
size: 'xs',
},
}
+
+export const WithAccessibleLabel: Story = {
+ args: {
+ value: 0.65,
+
+ variant: 'warning',
+
+ scoreLabel: 'AI confidence',
+ },
+}
diff --git a/src/shared/primitives/Skeleton/Skeleton.stories.tsx b/src/shared/primitives/Skeleton/Skeleton.stories.tsx
new file mode 100644
index 0000000..cd07e88
--- /dev/null
+++ b/src/shared/primitives/Skeleton/Skeleton.stories.tsx
@@ -0,0 +1,90 @@
+import type { Meta, StoryObj } from '@storybook/react-vite'
+
+import { Skeleton } from './Skeleton'
+
+const meta: Meta
= {
+ title: 'Shared/Primitives/Skeleton',
+
+ component: Skeleton,
+
+ tags: ['autodocs'],
+
+ parameters: {
+ layout: 'padded',
+ },
+
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+}
+
+export default meta
+
+type Story = StoryObj
+
+export const Text: Story = {
+ args: {
+ variant: 'text',
+ lines: 3,
+ },
+}
+
+export const Card: Story = {
+ args: {
+ variant: 'card',
+ },
+}
+
+export const Avatar: Story = {
+ args: {
+ variant: 'avatar',
+
+ width: 56,
+
+ height: 56,
+ },
+}
+
+export const Bar: Story = {
+ args: {
+ variant: 'bar',
+
+ width: '100%',
+ },
+}
+
+export const Custom: Story = {
+ args: {
+ variant: 'custom',
+
+ width: 240,
+
+ height: 80,
+
+ className: 'rounded-xl',
+ },
+}
+
+export const CardList: Story = {
+ render: () => (
+
+ {Array.from({
+ length: 3,
+ }).map((_, index) => (
+
+ ))}
+
+ ),
+}
+export const LoadingRegion: Story = {
+ render: () => (
+
+
+
+
+ ),
+}
diff --git a/src/shared/primitives/Skeleton/Skeleton.tsx b/src/shared/primitives/Skeleton/Skeleton.tsx
new file mode 100644
index 0000000..50ec516
--- /dev/null
+++ b/src/shared/primitives/Skeleton/Skeleton.tsx
@@ -0,0 +1,108 @@
+import React from 'react'
+
+import { cva } from 'class-variance-authority'
+
+export interface SkeletonProps {
+ variant?: 'text' | 'card' | 'avatar' | 'bar' | 'custom'
+
+ width?: string | number
+
+ height?: string | number
+
+ lines?: number
+
+ className?: string
+}
+
+const skeletonStyles = cva(
+ `
+ relative
+ overflow-hidden
+ rounded-md
+ bg-bg-tertiary
+ before:absolute
+ before:inset-0
+ before:-translate-x-full
+ before:animate-[skeletonShimmer_1.8s_infinite]
+ before:bg-gradient-to-r
+ before:from-transparent
+ before:via-bg-secondary
+ before:to-transparent
+ `,
+ {
+ variants: {
+ variant: {
+ text: 'h-4 w-full',
+
+ card: `
+ h-[160px]
+ w-full
+ rounded-xl
+ `,
+
+ avatar: 'rounded-full',
+
+ bar: `
+ h-2
+ rounded-full
+ `,
+
+ custom: '',
+ },
+ },
+
+ defaultVariants: {
+ variant: 'text',
+ },
+ }
+)
+
+export function Skeleton({
+ variant = 'text',
+
+ width,
+
+ height,
+
+ lines = 1,
+
+ className = '',
+}: SkeletonProps) {
+ if (variant === 'text') {
+ return (
+
+ {Array.from({
+ length: lines,
+ }).map((_, index) => (
+
1 ? '80%' : width,
+ height,
+ }}
+ />
+ ))}
+
+ )
+ }
+
+ return (
+
+ )
+}
+
+export default Skeleton
diff --git a/src/shared/primitives/Skeleton/index.ts b/src/shared/primitives/Skeleton/index.ts
new file mode 100644
index 0000000..5c93917
--- /dev/null
+++ b/src/shared/primitives/Skeleton/index.ts
@@ -0,0 +1,3 @@
+export { Skeleton } from './Skeleton'
+
+export type { SkeletonProps } from './Skeleton'
diff --git a/src/shared/primitives/Switch/Switch.stories.tsx b/src/shared/primitives/Switch/Switch.stories.tsx
index 39a7fa2..50aa8b8 100644
--- a/src/shared/primitives/Switch/Switch.stories.tsx
+++ b/src/shared/primitives/Switch/Switch.stories.tsx
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react-vite'
-
+import { useState } from 'react'
import { fn } from 'storybook/test'
import { Switch } from './Switch'
@@ -55,3 +55,14 @@ export const DisabledOn: Story = {
disabled: true,
},
}
+
+export const Interactive: Story = {
+ args: {
+ checked: false,
+ },
+ render: (args) => {
+ const [checked, setChecked] = useState(false)
+
+ return
+ },
+}
diff --git a/src/shared/primitives/Tooltip/Tooltip.stories.tsx b/src/shared/primitives/Tooltip/Tooltip.stories.tsx
index f84a861..4b46bb0 100644
--- a/src/shared/primitives/Tooltip/Tooltip.stories.tsx
+++ b/src/shared/primitives/Tooltip/Tooltip.stories.tsx
@@ -17,7 +17,12 @@ export default meta
type Story = StoryObj
const IconButton = () => (
-