@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.
- package/dist/_virtual/index2.js +2 -3
- package/dist/_virtual/index2.js.map +1 -1
- package/dist/_virtual/index3.js +3 -2
- package/dist/_virtual/index3.js.map +1 -1
- package/dist/components/atoms/alert-dialog.js +41 -0
- package/dist/components/atoms/alert-dialog.js.map +1 -0
- package/dist/components/atoms/thumbhash-image.js +54 -0
- package/dist/components/atoms/thumbhash-image.js.map +1 -0
- package/dist/components/commerce/merchant-card-skeleton.js +29 -0
- package/dist/components/commerce/merchant-card-skeleton.js.map +1 -0
- package/dist/components/commerce/merchant-card.js +28 -22
- package/dist/components/commerce/merchant-card.js.map +1 -1
- package/dist/components/commerce/product-card-skeleton.js +20 -0
- package/dist/components/commerce/product-card-skeleton.js.map +1 -0
- package/dist/components/commerce/product-card.js +105 -78
- package/dist/components/commerce/product-card.js.map +1 -1
- package/dist/components/navigation/transition-container.js +8 -0
- package/dist/components/navigation/transition-container.js.map +1 -0
- package/dist/components/navigation/transition-link.js +27 -0
- package/dist/components/navigation/transition-link.js.map +1 -0
- package/dist/components/ui/skeleton.js +16 -0
- package/dist/components/ui/skeleton.js.map +1 -0
- package/dist/hooks/navigation/useNavigateWithTransition.js +43 -0
- package/dist/hooks/navigation/useNavigateWithTransition.js.map +1 -0
- package/dist/hooks/navigation/useViewTransitions.js +45 -0
- package/dist/hooks/navigation/useViewTransitions.js.map +1 -0
- package/dist/index.js +215 -196
- package/dist/index.js.map +1 -1
- 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
- package/dist/shop-minis-react/node_modules/.pnpm/js-base64@3.7.7/node_modules/js-base64/base64.js +21 -0
- package/dist/shop-minis-react/node_modules/.pnpm/js-base64@3.7.7/node_modules/js-base64/base64.js.map +1 -0
- package/dist/shop-minis-react/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.js +1 -1
- 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
- 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
- package/dist/shop-minis-react/node_modules/.pnpm/thumbhash@0.1.1/node_modules/thumbhash/thumbhash.js +145 -0
- package/dist/shop-minis-react/node_modules/.pnpm/thumbhash@0.1.1/node_modules/thumbhash/thumbhash.js.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/image.js +15 -0
- package/dist/utils/image.js.map +1 -0
- package/package.json +13 -3
- package/src/components/atoms/alert-dialog.tsx +67 -0
- package/src/components/atoms/thumbhash-image.tsx +66 -0
- package/src/components/commerce/merchant-card-skeleton.tsx +31 -0
- package/src/components/commerce/merchant-card.tsx +5 -2
- package/src/components/commerce/product-card-skeleton.tsx +30 -0
- package/src/components/commerce/product-card.tsx +49 -8
- package/src/components/index.ts +8 -0
- package/src/components/navigation/transition-container.tsx +7 -0
- package/src/components/navigation/transition-link.tsx +48 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/navigation/useNavigateWithTransition.ts +62 -0
- package/src/hooks/navigation/useViewTransitions.ts +79 -0
- package/src/index.css +1 -0
- package/src/mocks.ts +8 -2
- package/src/stories/Accordion.stories.tsx +124 -0
- package/src/stories/Alert.stories.tsx +38 -0
- package/src/stories/AlertDialog.stories.tsx +48 -0
- package/src/stories/Avatar.stories.tsx +29 -0
- package/src/stories/Badge.stories.tsx +46 -0
- package/src/stories/Button.stories.tsx +81 -0
- package/src/stories/Card.stories.tsx +40 -0
- package/src/stories/Checkbox.stories.tsx +44 -0
- package/src/stories/FavoriteButton.stories.tsx +58 -0
- package/src/stories/IconButton.stories.tsx +68 -0
- package/src/stories/Input.stories.tsx +44 -0
- package/src/stories/Label.stories.tsx +19 -0
- package/src/stories/MerchantCard.stories.tsx +55 -0
- package/src/stories/ProductCard.stories.tsx +85 -0
- package/src/stories/ProductLink.stories.tsx +46 -0
- package/src/stories/Progress.stories.tsx +30 -0
- package/src/stories/RadioGroup.stories.tsx +51 -0
- package/src/stories/Select.stories.tsx +85 -0
- package/src/stories/Skeleton.stories.tsx +19 -0
- package/src/stories/Toaster.stories.tsx +46 -0
- package/src/stories/Touchable.stories.tsx +40 -0
- package/src/styles/animations.css +90 -0
- package/src/styles/globals.css +8 -0
- package/src/styles/theme.css +1 -1
- package/src/types/index.ts +7 -1
- 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}
|
package/src/hooks/index.ts
CHANGED
|
@@ -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
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 = {}
|