@shopify/shop-minis-react 0.0.18 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/_virtual/index2.js +2 -3
  2. package/dist/_virtual/index2.js.map +1 -1
  3. package/dist/_virtual/index3.js +3 -2
  4. package/dist/_virtual/index3.js.map +1 -1
  5. package/dist/components/atoms/alert-dialog.js +41 -0
  6. package/dist/components/atoms/alert-dialog.js.map +1 -0
  7. package/dist/components/atoms/thumbhash-image.js +54 -0
  8. package/dist/components/atoms/thumbhash-image.js.map +1 -0
  9. package/dist/components/commerce/merchant-card-skeleton.js +29 -0
  10. package/dist/components/commerce/merchant-card-skeleton.js.map +1 -0
  11. package/dist/components/commerce/merchant-card.js +28 -22
  12. package/dist/components/commerce/merchant-card.js.map +1 -1
  13. package/dist/components/commerce/product-card-skeleton.js +20 -0
  14. package/dist/components/commerce/product-card-skeleton.js.map +1 -0
  15. package/dist/components/commerce/product-card.js +105 -78
  16. package/dist/components/commerce/product-card.js.map +1 -1
  17. package/dist/components/navigation/transition-container.js +8 -0
  18. package/dist/components/navigation/transition-container.js.map +1 -0
  19. package/dist/components/navigation/transition-link.js +27 -0
  20. package/dist/components/navigation/transition-link.js.map +1 -0
  21. package/dist/components/ui/skeleton.js +16 -0
  22. package/dist/components/ui/skeleton.js.map +1 -0
  23. package/dist/hooks/navigation/useNavigateWithTransition.js +43 -0
  24. package/dist/hooks/navigation/useNavigateWithTransition.js.map +1 -0
  25. package/dist/hooks/navigation/useViewTransitions.js +45 -0
  26. package/dist/hooks/navigation/useViewTransitions.js.map +1 -0
  27. package/dist/index.js +215 -196
  28. package/dist/index.js.map +1 -1
  29. package/dist/shop-minis-react/node_modules/.pnpm/@radix-ui_react-use-is-hydrated@0.1.0_@types_react@19.1.6_react@19.1.0/node_modules/@radix-ui/react-use-is-hydrated/dist/index.js +1 -1
  30. package/dist/shop-minis-react/node_modules/.pnpm/js-base64@3.7.7/node_modules/js-base64/base64.js +21 -0
  31. package/dist/shop-minis-react/node_modules/.pnpm/js-base64@3.7.7/node_modules/js-base64/base64.js.map +1 -0
  32. package/dist/shop-minis-react/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.js +1 -1
  33. package/dist/shop-minis-react/node_modules/.pnpm/react-router@7.7.0_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/react-router/dist/development/chunk-EF7DTUVF.js +1298 -0
  34. package/dist/shop-minis-react/node_modules/.pnpm/react-router@7.7.0_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/react-router/dist/development/chunk-EF7DTUVF.js.map +1 -0
  35. package/dist/shop-minis-react/node_modules/.pnpm/thumbhash@0.1.1/node_modules/thumbhash/thumbhash.js +145 -0
  36. package/dist/shop-minis-react/node_modules/.pnpm/thumbhash@0.1.1/node_modules/thumbhash/thumbhash.js.map +1 -0
  37. package/dist/types/index.js +10 -0
  38. package/dist/types/index.js.map +1 -0
  39. package/dist/utils/image.js +15 -0
  40. package/dist/utils/image.js.map +1 -0
  41. package/package.json +13 -3
  42. package/src/components/atoms/alert-dialog.tsx +67 -0
  43. package/src/components/atoms/thumbhash-image.tsx +66 -0
  44. package/src/components/commerce/merchant-card-skeleton.tsx +31 -0
  45. package/src/components/commerce/merchant-card.tsx +5 -2
  46. package/src/components/commerce/product-card-skeleton.tsx +30 -0
  47. package/src/components/commerce/product-card.tsx +49 -8
  48. package/src/components/index.ts +8 -0
  49. package/src/components/navigation/transition-container.tsx +7 -0
  50. package/src/components/navigation/transition-link.tsx +48 -0
  51. package/src/components/ui/skeleton.tsx +13 -0
  52. package/src/hooks/index.ts +1 -0
  53. package/src/hooks/navigation/useNavigateWithTransition.ts +62 -0
  54. package/src/hooks/navigation/useViewTransitions.ts +79 -0
  55. package/src/index.css +1 -0
  56. package/src/mocks.ts +8 -2
  57. package/src/stories/Accordion.stories.tsx +124 -0
  58. package/src/stories/Alert.stories.tsx +38 -0
  59. package/src/stories/AlertDialog.stories.tsx +48 -0
  60. package/src/stories/Avatar.stories.tsx +29 -0
  61. package/src/stories/Badge.stories.tsx +46 -0
  62. package/src/stories/Button.stories.tsx +81 -0
  63. package/src/stories/Card.stories.tsx +40 -0
  64. package/src/stories/Checkbox.stories.tsx +44 -0
  65. package/src/stories/FavoriteButton.stories.tsx +58 -0
  66. package/src/stories/IconButton.stories.tsx +68 -0
  67. package/src/stories/Input.stories.tsx +44 -0
  68. package/src/stories/Label.stories.tsx +19 -0
  69. package/src/stories/MerchantCard.stories.tsx +55 -0
  70. package/src/stories/ProductCard.stories.tsx +85 -0
  71. package/src/stories/ProductLink.stories.tsx +46 -0
  72. package/src/stories/Progress.stories.tsx +30 -0
  73. package/src/stories/RadioGroup.stories.tsx +51 -0
  74. package/src/stories/Select.stories.tsx +85 -0
  75. package/src/stories/Skeleton.stories.tsx +19 -0
  76. package/src/stories/Toaster.stories.tsx +46 -0
  77. package/src/stories/Touchable.stories.tsx +40 -0
  78. package/src/styles/animations.css +90 -0
  79. package/src/styles/globals.css +8 -0
  80. package/src/styles/theme.css +1 -1
  81. package/src/types/index.ts +7 -1
  82. package/src/utils/image.ts +18 -0
@@ -0,0 +1,48 @@
1
+ import {forwardRef, AnchorHTMLAttributes} from 'react'
2
+
3
+ import {useHref} from 'react-router'
4
+
5
+ import {useNavigateWithTransition} from '../../hooks/navigation/useNavigateWithTransition'
6
+
7
+ type TransitionLinkProps = AnchorHTMLAttributes<HTMLAnchorElement> & {
8
+ to: string
9
+ }
10
+
11
+ const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i
12
+
13
+ export const TransitionLink = forwardRef<
14
+ HTMLAnchorElement,
15
+ TransitionLinkProps
16
+ >(({onClick, to, children, ...props}, forwardedRef) => {
17
+ const transitionNavigate = useNavigateWithTransition()
18
+
19
+ const isAbsolute = typeof to === 'string' && ABSOLUTE_URL_REGEX.test(to)
20
+
21
+ if (isAbsolute) {
22
+ console.warn(
23
+ `TransitionLink: absolute URLs are not supported. Please update to a valid relative path.`
24
+ )
25
+ }
26
+
27
+ const href = useHref(to)
28
+
29
+ const handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
30
+ if (onClick) onClick(event)
31
+
32
+ if (!event.defaultPrevented) {
33
+ event.preventDefault()
34
+ transitionNavigate(to)
35
+ }
36
+ }
37
+
38
+ return (
39
+ <a
40
+ {...props}
41
+ onClick={handleClick}
42
+ href={isAbsolute ? undefined : href}
43
+ ref={forwardedRef}
44
+ >
45
+ {children}
46
+ </a>
47
+ )
48
+ })
@@ -0,0 +1,13 @@
1
+ import {cn} from '../../lib/utils'
2
+
3
+ function Skeleton({className, ...props}: React.ComponentProps<'div'>) {
4
+ return (
5
+ <div
6
+ data-slot="skeleton"
7
+ className={cn('bg-accent animate-pulse rounded-md', className)}
8
+ {...props}
9
+ />
10
+ )
11
+ }
12
+
13
+ export {Skeleton}
@@ -31,6 +31,7 @@ export * from './storage/useImageUpload'
31
31
  export * from './navigation/useShopNavigation'
32
32
  export * from './navigation/useCloseMini'
33
33
  export * from './navigation/useDeeplink'
34
+ export * from './navigation/useNavigateWithTransition'
34
35
 
35
36
  // - Shop Hooks
36
37
  export * from './shop/useShop'
@@ -0,0 +1,62 @@
1
+ import {useLocation, useNavigate, NavigateOptions} from 'react-router'
2
+
3
+ import {DATA_NAVIGATION_TYPE_ATTRIBUTE} from '../../types'
4
+
5
+ export function useNavigateWithTransition() {
6
+ const navigate = useNavigate()
7
+ const location = useLocation()
8
+
9
+ const transitionNavigate = (
10
+ to: string | number,
11
+ options?: NavigateOptions
12
+ ) => {
13
+ if (typeof to === 'number') {
14
+ // Delta navigation - no options parameter
15
+ if (document.startViewTransition) {
16
+ const transition = document.startViewTransition(() => {
17
+ navigate(to)
18
+ })
19
+
20
+ transition.finished
21
+ .then(() => {
22
+ document.documentElement.removeAttribute(
23
+ DATA_NAVIGATION_TYPE_ATTRIBUTE
24
+ )
25
+ })
26
+ .catch(error => {
27
+ console.error('View transition error:', error)
28
+ })
29
+ } else {
30
+ return navigate(to)
31
+ }
32
+ return
33
+ }
34
+
35
+ const isSameRoute = to === location.pathname
36
+
37
+ // Path navigation - with options
38
+ if (document.startViewTransition) {
39
+ const transition = document.startViewTransition(() => {
40
+ navigate(to, {
41
+ preventScrollReset: true,
42
+ replace: isSameRoute,
43
+ ...options,
44
+ })
45
+ })
46
+
47
+ transition.finished
48
+ .then(() => {
49
+ document.documentElement.removeAttribute(
50
+ DATA_NAVIGATION_TYPE_ATTRIBUTE
51
+ )
52
+ })
53
+ .catch(error => {
54
+ console.error('View transition error:', error)
55
+ })
56
+ } else {
57
+ return navigate(to, options)
58
+ }
59
+ }
60
+
61
+ return transitionNavigate
62
+ }
@@ -0,0 +1,79 @@
1
+ import {useEffect} from 'react'
2
+
3
+ import {useNavigationType, useLocation} from 'react-router'
4
+
5
+ import {DATA_NAVIGATION_TYPE_ATTRIBUTE, NAVIGATION_TYPES} from '../../types'
6
+
7
+ export function useViewTransitions() {
8
+ const location = useLocation()
9
+ const navType = useNavigationType()
10
+
11
+ useEffect(() => {
12
+ let isAndroidBackPress = false
13
+
14
+ const handleAndroidBackPress = () => {
15
+ isAndroidBackPress = true
16
+
17
+ if (document.startViewTransition) {
18
+ const transition = document.startViewTransition(() => {
19
+ document.documentElement.setAttribute(
20
+ DATA_NAVIGATION_TYPE_ATTRIBUTE,
21
+ NAVIGATION_TYPES.backward
22
+ )
23
+ })
24
+
25
+ transition.finished
26
+ .then(() => {
27
+ document.documentElement.removeAttribute(
28
+ DATA_NAVIGATION_TYPE_ATTRIBUTE
29
+ )
30
+ })
31
+ .catch(error => {
32
+ console.error('View transition error:', error)
33
+ })
34
+ }
35
+ }
36
+
37
+ const handlePopstate = (event: PopStateEvent) => {
38
+ // If the ios back gesture is used, we don't want to trigger view transition
39
+ if (event.hasUAVisualTransition && !isAndroidBackPress) {
40
+ document.documentElement.setAttribute(
41
+ DATA_NAVIGATION_TYPE_ATTRIBUTE,
42
+ NAVIGATION_TYPES.none
43
+ )
44
+ }
45
+ }
46
+
47
+ window.addEventListener('androidbackpressed', handleAndroidBackPress)
48
+ window.addEventListener('popstate', handlePopstate)
49
+
50
+ return () => {
51
+ window.removeEventListener('popstate', handlePopstate)
52
+ window.removeEventListener('androidbackpressed', handleAndroidBackPress)
53
+ }
54
+ }, [location])
55
+
56
+ useEffect(() => {
57
+ const currentNavType = document.documentElement.getAttribute(
58
+ DATA_NAVIGATION_TYPE_ATTRIBUTE
59
+ )
60
+
61
+ if (!currentNavType) {
62
+ if (navType === 'PUSH') {
63
+ document.documentElement.setAttribute(
64
+ DATA_NAVIGATION_TYPE_ATTRIBUTE,
65
+ NAVIGATION_TYPES.forward
66
+ )
67
+ } else if (navType === 'POP') {
68
+ document.documentElement.setAttribute(
69
+ DATA_NAVIGATION_TYPE_ATTRIBUTE,
70
+ NAVIGATION_TYPES.backward
71
+ )
72
+ }
73
+ }
74
+
75
+ return () => {
76
+ document.documentElement.removeAttribute(DATA_NAVIGATION_TYPE_ATTRIBUTE)
77
+ }
78
+ }, [navType, location])
79
+ }
package/src/index.css CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  @import './styles/theme.css';
5
5
  @import './styles/globals.css';
6
+ @import './styles/animations.css';
6
7
 
7
8
  /* When consumed as npm package, this path resolves from the consuming app's location */
8
9
  @source '../node_modules/@shopify/shop-minis-react/src';
package/src/mocks.ts CHANGED
@@ -2,7 +2,7 @@ import {Product, Gender} from '@shopify/shop-minis-platform'
2
2
  import {ShopActions} from '@shopify/shop-minis-platform/actions'
3
3
 
4
4
  // Helper functions for common data structures
5
- const createProduct = (
5
+ export const createProduct = (
6
6
  id: string,
7
7
  title: string,
8
8
  price = '99.99',
@@ -21,7 +21,7 @@ const createProduct = (
21
21
  featuredImage: {url: `https://picsum.photos/400/400`, altText: title},
22
22
  })
23
23
 
24
- const createShop = (id: string, name: string) => ({
24
+ export const createShop = (id: string, name: string) => ({
25
25
  id,
26
26
  name,
27
27
  isFollowing: false,
@@ -29,6 +29,11 @@ const createShop = (id: string, name: string) => ({
29
29
  url: `https://${name.toLowerCase().replace(/\s+/g, '-')}.com`,
30
30
  },
31
31
  reviewAnalytics: {averageRating: 4.3, reviewCount: 50},
32
+ visualTheme: {
33
+ id: 'visual-theme-1',
34
+ featuredImages: [{url: `https://picsum.photos/400/400`, sensitive: false}],
35
+ logoImage: {url: `https://picsum.photos/100/400`, sensitive: false},
36
+ },
32
37
  })
33
38
 
34
39
  const createPagination = (hasNext = false) => ({
@@ -288,6 +293,7 @@ export const injectMocks = () => {
288
293
  window.minisParams = {
289
294
  handle: 'mock-handle',
290
295
  initialUrl: '/mock-initial-url',
296
+ platform: 'ios',
291
297
  }
292
298
  }
293
299
 
@@ -0,0 +1,124 @@
1
+ import {
2
+ Accordion,
3
+ AccordionContent,
4
+ AccordionItem,
5
+ AccordionTrigger,
6
+ } from '../components/ui/accordion'
7
+
8
+ import type {Meta, StoryObj} from '@storybook/react-vite'
9
+
10
+ const meta = {
11
+ title: 'UI/Accordion',
12
+ component: Accordion,
13
+ parameters: {},
14
+ args: {
15
+ type: 'single',
16
+ collapsible: false,
17
+ },
18
+ tags: ['autodocs'],
19
+ } satisfies Meta<typeof Accordion>
20
+
21
+ export default meta
22
+ type Story = StoryObj<typeof meta>
23
+
24
+ export const NonCollapsible: Story = {
25
+ args: {
26
+ type: 'single',
27
+ collapsible: false,
28
+ },
29
+ render: args => (
30
+ <Accordion {...args}>
31
+ <AccordionItem value="item-2">
32
+ <AccordionTrigger>Can i collapse this?</AccordionTrigger>
33
+ <AccordionContent>
34
+ No. When you set the collapsible prop to false, the accordion is not
35
+ collapsible.
36
+ </AccordionContent>
37
+ </AccordionItem>
38
+ </Accordion>
39
+ ),
40
+ }
41
+
42
+ export const Collapsible: Story = {
43
+ args: {
44
+ type: 'single',
45
+ collapsible: true,
46
+ },
47
+ render: args => (
48
+ <Accordion {...args}>
49
+ <AccordionItem value="item-2">
50
+ <AccordionTrigger>Can i collapse this?</AccordionTrigger>
51
+ <AccordionContent>
52
+ Yes. When you set the collapsible prop to true, you can collapse the
53
+ </AccordionContent>
54
+ </AccordionItem>
55
+ </Accordion>
56
+ ),
57
+ }
58
+
59
+ export const Single: Story = {
60
+ args: {
61
+ type: 'single',
62
+ },
63
+ render: args => (
64
+ <Accordion {...args}>
65
+ <AccordionItem value="item-1">
66
+ <AccordionTrigger>Single item only</AccordionTrigger>
67
+ <AccordionContent>
68
+ With the single type, only one item can be open at a time.
69
+ </AccordionContent>
70
+ </AccordionItem>
71
+ <AccordionItem value="item-2">
72
+ <AccordionTrigger>Another item</AccordionTrigger>
73
+ <AccordionContent>
74
+ Opening this item will close the previous one.
75
+ </AccordionContent>
76
+ </AccordionItem>
77
+ </Accordion>
78
+ ),
79
+ }
80
+
81
+ export const Multiple: Story = {
82
+ args: {
83
+ type: 'multiple',
84
+ },
85
+ render: args => (
86
+ <Accordion {...args}>
87
+ <AccordionItem value="item-1">
88
+ <AccordionTrigger>Can I open multiple items?</AccordionTrigger>
89
+ <AccordionContent>
90
+ Yes, you can open multiple items at the same time with the multiple
91
+ type.
92
+ </AccordionContent>
93
+ </AccordionItem>
94
+ <AccordionItem value="item-2">
95
+ <AccordionTrigger>Is it customizable?</AccordionTrigger>
96
+ <AccordionContent>
97
+ Yes, you can customize the styling and behavior to match your needs.
98
+ </AccordionContent>
99
+ </AccordionItem>
100
+ <AccordionItem value="item-1">
101
+ <AccordionTrigger>Long content example</AccordionTrigger>
102
+ <AccordionContent>
103
+ <div className="space-y-4">
104
+ <p>
105
+ This is a longer content example that demonstrates how the
106
+ accordion handles substantial amounts of text and content.
107
+ </p>
108
+ <p>
109
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
110
+ eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
111
+ enim ad minim veniam, quis nostrud exercitation ullamco laboris
112
+ nisi ut aliquip ex ea commodo consequat.
113
+ </p>
114
+ <ul className="list-disc list-inside space-y-1">
115
+ <li>First item in the list</li>
116
+ <li>Second item in the list</li>
117
+ <li>Third item in the list</li>
118
+ </ul>
119
+ </div>
120
+ </AccordionContent>
121
+ </AccordionItem>
122
+ </Accordion>
123
+ ),
124
+ }
@@ -0,0 +1,38 @@
1
+ import {Alert, AlertTitle, AlertDescription} from '../components/ui/alert'
2
+
3
+ import type {Meta, StoryObj} from '@storybook/react-vite'
4
+
5
+ const meta = {
6
+ title: 'UI/Alert',
7
+ render: ({variant}) => (
8
+ <Alert variant={variant}>
9
+ <AlertTitle>Alert Title</AlertTitle>
10
+ <AlertDescription>
11
+ This is a default alert with a title and description.
12
+ </AlertDescription>
13
+ </Alert>
14
+ ),
15
+
16
+ parameters: {},
17
+ tags: ['autodocs'],
18
+ argTypes: {
19
+ variant: {
20
+ control: 'radio',
21
+ options: ['default', 'destructive'],
22
+ },
23
+ },
24
+ } satisfies Meta<typeof Alert>
25
+
26
+ export default meta
27
+ type Story = StoryObj<typeof meta>
28
+
29
+ export const Default: Story = {
30
+ args: {
31
+ variant: 'default',
32
+ },
33
+ }
34
+ export const Destructive: Story = {
35
+ args: {
36
+ variant: 'destructive',
37
+ },
38
+ }
@@ -0,0 +1,48 @@
1
+ import {fn} from 'storybook/test'
2
+
3
+ import {
4
+ AlertDialog,
5
+ AlertDialogAction,
6
+ AlertDialogCancel,
7
+ AlertDialogContent,
8
+ AlertDialogDescription,
9
+ AlertDialogFooter,
10
+ AlertDialogHeader,
11
+ AlertDialogTitle,
12
+ AlertDialogTrigger,
13
+ Button,
14
+ } from '../components'
15
+
16
+ import type {Meta, StoryObj} from '@storybook/react-vite'
17
+
18
+ const meta = {
19
+ title: 'Ui/AlertDialog',
20
+ render: () => (
21
+ <AlertDialog>
22
+ <AlertDialogTrigger asChild>
23
+ <Button variant="outline">Open Alert Dialog</Button>
24
+ </AlertDialogTrigger>
25
+ <AlertDialogContent>
26
+ <AlertDialogHeader>
27
+ <AlertDialogTitle>Are you sure?</AlertDialogTitle>
28
+ <AlertDialogDescription>
29
+ This action cannot be undone.
30
+ </AlertDialogDescription>
31
+ </AlertDialogHeader>
32
+ <AlertDialogFooter>
33
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
34
+ <AlertDialogAction onClick={() => fn()}>Continue</AlertDialogAction>
35
+ </AlertDialogFooter>
36
+ </AlertDialogContent>
37
+ </AlertDialog>
38
+ ),
39
+ parameters: {},
40
+ tags: ['autodocs'],
41
+ argTypes: {},
42
+ args: {},
43
+ } satisfies Meta<typeof AlertDialog>
44
+
45
+ export default meta
46
+ type Story = StoryObj<typeof meta>
47
+
48
+ export const Default: Story = {}
@@ -0,0 +1,29 @@
1
+ import {Avatar, AvatarFallback, AvatarImage} from '../components/ui/avatar'
2
+
3
+ import type {StoryObj} from '@storybook/react-vite'
4
+
5
+ interface AvatarProps {
6
+ src: 'https://github.com/shadcn.png'
7
+ userInitials: string
8
+ }
9
+
10
+ const meta = {
11
+ title: 'UI/Avatar',
12
+ render: ({userInitials}: AvatarProps) => (
13
+ <Avatar>
14
+ <AvatarImage src="https://github.com/shadcn.png" />
15
+ <AvatarFallback>{userInitials}</AvatarFallback>
16
+ </Avatar>
17
+ ),
18
+ args: {
19
+ className: 'size-12',
20
+ src: 'https://github.com/shadcn.png',
21
+ userInitials: 'CN',
22
+ },
23
+ tags: ['autodocs'],
24
+ }
25
+
26
+ export default meta
27
+ type Story = StoryObj<typeof meta>
28
+
29
+ export const Default: Story = {}
@@ -0,0 +1,46 @@
1
+ import {Badge} from '../components/ui/badge'
2
+
3
+ import type {Meta, StoryObj} from '@storybook/react-vite'
4
+
5
+ const meta = {
6
+ title: 'UI/Badge',
7
+ component: Badge,
8
+ parameters: {},
9
+ tags: ['autodocs'],
10
+ argTypes: {
11
+ variant: {
12
+ control: 'radio',
13
+ options: ['default', 'secondary', 'destructive', 'outline'],
14
+ },
15
+ },
16
+ } satisfies Meta<typeof Badge>
17
+
18
+ export default meta
19
+ type Story = StoryObj<typeof meta>
20
+
21
+ export const Default: Story = {
22
+ args: {
23
+ children: 'Badge',
24
+ },
25
+ }
26
+
27
+ export const Secondary: Story = {
28
+ args: {
29
+ variant: 'secondary',
30
+ children: 'Badge',
31
+ },
32
+ }
33
+
34
+ export const Destructive: Story = {
35
+ args: {
36
+ variant: 'destructive',
37
+ children: 'Badge',
38
+ },
39
+ }
40
+
41
+ export const Outline: Story = {
42
+ args: {
43
+ variant: 'outline',
44
+ children: 'Badge',
45
+ },
46
+ }
@@ -0,0 +1,81 @@
1
+ import {fn} from 'storybook/test'
2
+
3
+ import {Button} from '../components/atoms/button'
4
+
5
+ import type {Meta, StoryObj} from '@storybook/react-vite'
6
+
7
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
8
+ const meta = {
9
+ title: 'Atoms/Button',
10
+ component: Button,
11
+ parameters: {},
12
+ // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
13
+ tags: ['autodocs'],
14
+ argTypes: {
15
+ variant: {
16
+ control: 'radio',
17
+ options: [
18
+ 'default',
19
+ 'secondary',
20
+ 'tertiary',
21
+ 'outline',
22
+ 'ghost',
23
+ 'link',
24
+ 'destructive',
25
+ ],
26
+ },
27
+ },
28
+ args: {onClick: fn()},
29
+ } satisfies Meta<typeof Button>
30
+
31
+ export default meta
32
+ type Story = StoryObj<typeof meta>
33
+
34
+ export const Default: Story = {
35
+ args: {
36
+ variant: 'default',
37
+ children: 'Button',
38
+ },
39
+ }
40
+
41
+ export const Secondary: Story = {
42
+ args: {
43
+ variant: 'secondary',
44
+ children: 'Button',
45
+ },
46
+ }
47
+
48
+ export const Tertiary: Story = {
49
+ args: {
50
+ variant: 'tertiary',
51
+ children: 'Button',
52
+ },
53
+ }
54
+
55
+ export const Outline: Story = {
56
+ args: {
57
+ variant: 'outline',
58
+ children: 'Button',
59
+ },
60
+ }
61
+
62
+ export const Ghost: Story = {
63
+ args: {
64
+ variant: 'ghost',
65
+ children: 'Button',
66
+ },
67
+ }
68
+
69
+ export const Link: Story = {
70
+ args: {
71
+ variant: 'link',
72
+ children: 'Button',
73
+ },
74
+ }
75
+
76
+ export const Destructive: Story = {
77
+ args: {
78
+ variant: 'destructive',
79
+ children: 'Button',
80
+ },
81
+ }
@@ -0,0 +1,40 @@
1
+ import {Button} from '../components/atoms/button'
2
+ import {
3
+ Card,
4
+ CardHeader,
5
+ CardFooter,
6
+ CardTitle,
7
+ CardAction,
8
+ CardDescription,
9
+ CardContent,
10
+ } from '../components/ui/card'
11
+
12
+ import type {Meta, StoryObj} from '@storybook/react-vite'
13
+
14
+ const meta = {
15
+ title: 'UI/Card',
16
+ render: () => (
17
+ <Card>
18
+ <CardHeader>
19
+ <CardTitle>Card Title</CardTitle>
20
+ <CardDescription>Card description goes here</CardDescription>
21
+ <CardAction>
22
+ <Button>Action</Button>
23
+ </CardAction>
24
+ </CardHeader>
25
+ <CardContent>
26
+ <p>This is the main content of the card.</p>
27
+ </CardContent>
28
+ <CardFooter>
29
+ <p>Card footer content</p>
30
+ </CardFooter>
31
+ </Card>
32
+ ),
33
+ parameters: {},
34
+ tags: ['autodocs'],
35
+ } satisfies Meta<typeof Card>
36
+
37
+ export default meta
38
+ type Story = StoryObj<typeof meta>
39
+
40
+ export const Default: Story = {}