git.iko.soy/rowtype-yoga/purescript-yoga-heroui3
on main help sign in
wave 5 (table/pagination/breadcrumbs/progress/alert/toast) + hooks + umbrella + tests + button story
5c08d85Mark
test/HeroUI/Accordion/Stories.pursnew file+29
@@ -0,0 +1,29 @@
1+module HeroUI.Accordion.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Accordion as Accordion
7+import Yoga.React (component)
8+import Yoga.React.DOM.HTML (div)
9+import Yoga.React.DOM.Internal (text)
10+import YogaStories.Story (story)
11+
12+item :: String -> String -> String -> JSX
13+item key heading body =
14+ Accordion.accordionItem { id: key }
15+ [ Accordion.accordionHeading {} [ Accordion.accordionTrigger {} (text heading) ]
16+ , Accordion.accordionPanel {} [ Accordion.accordionBody {} (text body) ]
17+ ]
18+
19+mkAccordion :: {} -> JSX
20+mkAccordion = component "AccordionStory" \(_ :: {}) -> React.do
21+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-80" }
22+ [ Accordion.accordion { variant: Accordion.Default, defaultExpandedKeys: [ "a" ] }
23+ [ item "a" "First" "First panel body."
24+ , item "b" "Second" "Second panel body."
25+ ]
26+ ]
27+
28+basic :: JSX
29+basic = story "basic" mkAccordion {}
test/HeroUI/Alert/Stories.pursnew file+41
@@ -0,0 +1,41 @@
1+module HeroUI.Alert.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import Data.Generic.Rep (class Generic)
6+import React.Basic (JSX)
7+import HeroUI.Alert as Alert
8+import HeroUI.Types as T
9+import Yoga.React (component)
10+import Yoga.React.DOM.HTML (div)
11+import Yoga.React.DOM.Internal (text)
12+import YogaStories.Controls (enum)
13+import YogaStories.Story (story)
14+
15+data Status = Default | Accent | Success | Warning | Danger
16+
17+derive instance Generic Status _
18+
19+toStatus :: Status -> T.Color
20+toStatus = case _ of
21+ Default -> T.Default
22+ Accent -> T.Accent
23+ Success -> T.Success
24+ Warning -> T.Warning
25+ Danger -> T.Danger
26+
27+mkAlert :: { title :: String, body :: String, status :: Status } -> JSX
28+mkAlert = component "AlertStory" \props -> React.do
29+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-96" }
30+ [ Alert.alert { status: toStatus props.status }
31+ [ Alert.alertIndicator {} ([] :: Array JSX)
32+ , Alert.alertContent {}
33+ [ Alert.alertTitle {} (text props.title)
34+ , Alert.alertDescription {} (text props.body)
35+ ]
36+ ]
37+ ]
38+
39+basic :: JSX
40+basic = story "basic" mkAlert
41+ { title: "Heads up", body: "Your changes were saved.", status: enum Success }
test/HeroUI/Autocomplete/Stories.pursnew file+28
@@ -0,0 +1,28 @@
1+module HeroUI.Autocomplete.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Autocomplete as Autocomplete
7+import HeroUI.ListBox as ListBox
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkAutocomplete :: { placeholder :: String } -> JSX
14+mkAutocomplete = component "AutocompleteStory" \props -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-64" }
16+ [ Autocomplete.autocomplete { placeholder: props.placeholder }
17+ [ Autocomplete.autocompleteTrigger {} ([] :: Array JSX)
18+ , Autocomplete.autocompletePopover {}
19+ [ ListBox.listBox {}
20+ [ ListBox.listBoxItem { id: "apple" } (text "Apple")
21+ , ListBox.listBoxItem { id: "banana" } (text "Banana")
22+ ]
23+ ]
24+ ]
25+ ]
26+
27+basic :: JSX
28+basic = story "basic" mkAutocomplete { placeholder: "Search fruit" }
test/HeroUI/Avatar/Stories.pursnew file+21
@@ -0,0 +1,21 @@
1+module HeroUI.Avatar.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Avatar as Avatar
7+import HeroUI.Types as T
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkAvatar :: { initials :: String } -> JSX
14+mkAvatar = component "AvatarStory" \props -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg flex items-center gap-4" }
16+ [ Avatar.avatar { color: T.Accent, size: T.Md, variant: Avatar.Soft }
17+ [ Avatar.avatarFallback { color: T.Accent } (text props.initials) ]
18+ ]
19+
20+basic :: JSX
21+basic = story "basic" mkAvatar { initials: "ME" }
test/HeroUI/Badge/Stories.pursnew file+24
@@ -0,0 +1,24 @@
1+module HeroUI.Badge.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Avatar as Avatar
7+import HeroUI.Badge as Badge
8+import HeroUI.Types as T
9+import Yoga.React (component)
10+import Yoga.React.DOM.HTML (div)
11+import Yoga.React.DOM.Internal (text)
12+import YogaStories.Story (story)
13+
14+mkBadge :: { count :: String } -> JSX
15+mkBadge = component "BadgeStory" \props -> React.do
16+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg flex items-center gap-4" }
17+ [ Badge.badge { color: T.Danger, variant: Badge.Primary, placement: Badge.TopRight, size: T.Md }
18+ [ Badge.badgeLabel {} (text props.count)
19+ , Badge.badgeAnchor {} [ Avatar.avatar { color: T.Accent } [ Avatar.avatarFallback {} (text "ME") ] ]
20+ ]
21+ ]
22+
23+basic :: JSX
24+basic = story "basic" mkBadge { count: "5" }
test/HeroUI/Breadcrumbs/Stories.pursnew file+23
@@ -0,0 +1,23 @@
1+module HeroUI.Breadcrumbs.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Breadcrumbs as Breadcrumbs
7+import Yoga.React (component)
8+import Yoga.React.DOM.HTML (div)
9+import Yoga.React.DOM.Internal (text)
10+import YogaStories.Story (story)
11+
12+mkBreadcrumbs :: {} -> JSX
13+mkBreadcrumbs = component "BreadcrumbsStory" \(_ :: {}) -> React.do
14+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
15+ [ Breadcrumbs.breadcrumbs {}
16+ [ Breadcrumbs.breadcrumbsItem { href: "#" } (text "Home")
17+ , Breadcrumbs.breadcrumbsItem { href: "#" } (text "Library")
18+ , Breadcrumbs.breadcrumbsItem {} (text "Current")
19+ ]
20+ ]
21+
22+basic :: JSX
23+basic = story "basic" mkBreadcrumbs {}
test/HeroUI/Calendar/Stories.pursnew file+17
@@ -0,0 +1,17 @@
1+module HeroUI.Calendar.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Calendar as Calendar
7+import Yoga.React (component)
8+import Yoga.React.DOM.HTML (div)
9+import YogaStories.Story (story)
10+
11+mkCalendar :: {} -> JSX
12+mkCalendar = component "CalendarStory" \(_ :: {}) -> React.do
13+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
14+ [ Calendar.calendar {} ([] :: Array JSX) ]
15+
16+basic :: JSX
17+basic = story "basic" mkCalendar {}
test/HeroUI/Card/Stories.pursnew file+37
@@ -0,0 +1,37 @@
1+module HeroUI.Card.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import Data.Generic.Rep (class Generic)
6+import React.Basic (JSX)
7+import HeroUI.Card as Card
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Controls (enum)
12+import YogaStories.Story (story)
13+
14+data Variant = Default | Secondary | Tertiary | Transparent
15+
16+derive instance Generic Variant _
17+
18+toVariant :: Variant -> Card.Variant
19+toVariant = case _ of
20+ Default -> Card.Default
21+ Secondary -> Card.Secondary
22+ Tertiary -> Card.Tertiary
23+ Transparent -> Card.Transparent
24+
25+mkCard :: { title :: String, body :: String, variant :: Variant } -> JSX
26+mkCard = component "CardStory" \props -> React.do
27+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
28+ [ Card.card { variant: toVariant props.variant, className: "max-w-sm" }
29+ [ Card.cardHeader {} [ Card.cardTitle {} (text props.title) ]
30+ , Card.cardContent {} (text props.body)
31+ , Card.cardFooter {} (text "Footer")
32+ ]
33+ ]
34+
35+basic :: JSX
36+basic = story "basic" mkCard
37+ { title: "Card title", body: "Some descriptive body text.", variant: enum Default }
test/HeroUI/Checkbox/Stories.pursnew file+19
@@ -0,0 +1,19 @@
1+module HeroUI.Checkbox.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Checkbox as Checkbox
7+import HeroUI.Types as T
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkCheckbox :: { label :: String, defaultSelected :: Boolean } -> JSX
14+mkCheckbox = component "CheckboxStory" \props -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
16+ [ Checkbox.checkbox { defaultSelected: props.defaultSelected, variant: T.Primary } (text props.label) ]
17+
18+basic :: JSX
19+basic = story "basic" mkCheckbox { label: "Accept terms", defaultSelected: false }
test/HeroUI/Chip/Stories.pursnew file+32
@@ -0,0 +1,32 @@
1+module HeroUI.Chip.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import Data.Generic.Rep (class Generic)
6+import React.Basic (JSX)
7+import HeroUI.Chip as Chip
8+import HeroUI.Types as T
9+import Yoga.React (component)
10+import Yoga.React.DOM.HTML (div)
11+import Yoga.React.DOM.Internal (text)
12+import YogaStories.Controls (enum)
13+import YogaStories.Story (story)
14+
15+data Variant = Primary | Secondary | Tertiary | Soft
16+
17+derive instance Generic Variant _
18+
19+toVariant :: Variant -> Chip.Variant
20+toVariant = case _ of
21+ Primary -> Chip.Primary
22+ Secondary -> Chip.Secondary
23+ Tertiary -> Chip.Tertiary
24+ Soft -> Chip.Soft
25+
26+mkChip :: { label :: String, variant :: Variant } -> JSX
27+mkChip = component "ChipStory" \props -> React.do
28+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg flex items-center gap-4" }
29+ [ Chip.chip { color: T.Accent, size: T.Md, variant: toVariant props.variant } (text props.label) ]
30+
31+basic :: JSX
32+basic = story "basic" mkChip { label: "new", variant: enum Soft }
test/HeroUI/DateField/Stories.pursnew file+17
@@ -0,0 +1,17 @@
1+module HeroUI.DateField.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.DateField as DateField
7+import Yoga.React (component)
8+import Yoga.React.DOM.HTML (div)
9+import YogaStories.Story (story)
10+
11+mkDateField :: {} -> JSX
12+mkDateField = component "DateFieldStory" \(_ :: {}) -> React.do
13+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-72" }
14+ [ DateField.dateField { granularity: DateField.Day } ([] :: Array JSX) ]
15+
16+basic :: JSX
17+basic = story "basic" mkDateField {}
test/HeroUI/DatePicker/Stories.pursnew file+22
@@ -0,0 +1,22 @@
1+module HeroUI.DatePicker.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.DatePicker as DatePicker
7+import Yoga.React (component)
8+import Yoga.React.DOM.HTML (div)
9+import Yoga.React.DOM.Internal (text)
10+import YogaStories.Story (story)
11+
12+mkDatePicker :: {} -> JSX
13+mkDatePicker = component "DatePickerStory" \(_ :: {}) -> React.do
14+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-72" }
15+ [ DatePicker.datePicker {}
16+ [ DatePicker.datePickerTrigger {} (text "Pick a date")
17+ , DatePicker.datePickerPopover {} ([] :: Array JSX)
18+ ]
19+ ]
20+
21+basic :: JSX
22+basic = story "basic" mkDatePicker {}
test/HeroUI/Drawer/Stories.pursnew file+31
@@ -0,0 +1,31 @@
1+module HeroUI.Drawer.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Button as Btn
7+import HeroUI.Drawer as Drawer
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkDrawer :: { title :: String } -> JSX
14+mkDrawer = component "DrawerStory" \props -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
16+ [ Drawer.drawer {}
17+ [ Btn.button { variant: Btn.Primary } (text "Open drawer")
18+ , Drawer.drawerBackdrop { variant: Drawer.Blur }
19+ [ Drawer.drawerContent { placement: Drawer.Right }
20+ [ Drawer.drawerDialog {}
21+ [ Drawer.drawerHeader {} [ Drawer.drawerHeading {} (text props.title) ]
22+ , Drawer.drawerBody {} (text "Drawer body content.")
23+ , Drawer.drawerFooter {} [ Drawer.drawerCloseTrigger {} (text "Close") ]
24+ ]
25+ ]
26+ ]
27+ ]
28+ ]
29+
30+basic :: JSX
31+basic = story "basic" mkDrawer { title: "Settings" }
test/HeroUI/Dropdown/Stories.pursnew file+30
@@ -0,0 +1,30 @@
1+module HeroUI.Dropdown.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Button as Btn
7+import HeroUI.Dropdown as Dropdown
8+import HeroUI.Types as T
9+import Yoga.React (component)
10+import Yoga.React.DOM.HTML (div)
11+import Yoga.React.DOM.Internal (text)
12+import YogaStories.Story (story)
13+
14+mkDropdown :: {} -> JSX
15+mkDropdown = component "DropdownStory" \(_ :: {}) -> React.do
16+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
17+ [ Dropdown.dropdown {}
18+ [ Dropdown.dropdownTrigger {} [ Btn.button { variant: Btn.Primary } (text "Actions") ]
19+ , Dropdown.dropdownPopover {}
20+ [ Dropdown.dropdownMenu { selectionMode: T.SelectionNone }
21+ [ Dropdown.dropdownItem { id: "new" } (text "New file")
22+ , Dropdown.dropdownItem { id: "copy" } (text "Copy link")
23+ , Dropdown.dropdownItem { id: "delete" } (text "Delete")
24+ ]
25+ ]
26+ ]
27+ ]
28+
29+basic :: JSX
30+basic = story "basic" mkDropdown {}
test/HeroUI/Form/Stories.pursnew file+25
@@ -0,0 +1,25 @@
1+module HeroUI.Form.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Button as Btn
7+import HeroUI.Form as Form
8+import HeroUI.Input as Input
9+import Yoga.React (component)
10+import Yoga.React.DOM.HTML (div)
11+import Yoga.React.DOM.Internal (text)
12+import YogaStories.Story (story)
13+
14+mkForm :: {} -> JSX
15+mkForm = component "FormStory" \(_ :: {}) -> React.do
16+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-72" }
17+ [ Form.form { validationBehavior: Form.Native, className: "flex flex-col gap-3" }
18+ [ Input.textField { name: "email" }
19+ [ Input.input { placeholder: "you@example.com", type: Input.InputTypeEmail } ([] :: Array JSX) ]
20+ , Btn.button { type: Btn.ButtonTypeSubmit, variant: Btn.Primary } (text "Submit")
21+ ]
22+ ]
23+
24+basic :: JSX
25+basic = story "basic" mkForm {}
test/HeroUI/Input/Stories.pursnew file+31
@@ -0,0 +1,31 @@
1+module HeroUI.Input.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import Data.Generic.Rep (class Generic)
6+import React.Basic (JSX)
7+import HeroUI.Input as Input
8+import HeroUI.Types as T
9+import Yoga.React (component)
10+import Yoga.React.DOM.HTML (div)
11+import YogaStories.Controls (enum)
12+import YogaStories.Story (story)
13+
14+data Variant = Primary | Secondary
15+
16+derive instance Generic Variant _
17+
18+toVariant :: Variant -> T.FieldVariant
19+toVariant = case _ of
20+ Primary -> T.Primary
21+ Secondary -> T.Secondary
22+
23+mkInput :: { placeholder :: String, variant :: Variant } -> JSX
24+mkInput = component "InputStory" \props -> React.do
25+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-72" }
26+ [ Input.textField { variant: toVariant props.variant }
27+ [ Input.input { placeholder: props.placeholder, type: Input.InputTypeText } ([] :: Array JSX) ]
28+ ]
29+
30+basic :: JSX
31+basic = story "basic" mkInput { placeholder: "Type here…", variant: enum Primary }
test/HeroUI/InputOTP/Stories.pursnew file+22
@@ -0,0 +1,22 @@
1+module HeroUI.InputOTP.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import Data.Array ((..))
6+import React.Basic (JSX)
7+import HeroUI.InputOTP as InputOTP
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import YogaStories.Story (story)
11+
12+mkInputOTP :: { length :: Int } -> JSX
13+mkInputOTP = component "InputOTPStory" \props -> React.do
14+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
15+ [ InputOTP.inputOTP { maxLength: props.length }
16+ [ InputOTP.inputOTPGroup {}
17+ (map (\i -> InputOTP.inputOTPSlot { index: i } ([] :: Array JSX)) (0 .. (props.length - 1)))
18+ ]
19+ ]
20+
21+basic :: JSX
22+basic = story "basic" mkInputOTP { length: 4 }
test/HeroUI/Kbd/Stories.pursnew file+22
@@ -0,0 +1,22 @@
1+module HeroUI.Kbd.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Kbd as Kbd
7+import Yoga.React (component)
8+import Yoga.React.DOM.HTML (div)
9+import Yoga.React.DOM.Internal (text)
10+import YogaStories.Story (story)
11+
12+mkKbd :: { label :: String } -> JSX
13+mkKbd = component "KbdStory" \props -> React.do
14+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg flex items-center gap-2" }
15+ [ Kbd.kbd { variant: Kbd.Default }
16+ [ Kbd.kbdAbbr { keyValue: Kbd.Command } ([] :: Array JSX)
17+ , Kbd.kbdContent {} (text props.label)
18+ ]
19+ ]
20+
21+basic :: JSX
22+basic = story "basic" mkKbd { label: "K" }
test/HeroUI/Link/Stories.pursnew file+18
@@ -0,0 +1,18 @@
1+module HeroUI.Link.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Link as Link
7+import Yoga.React (component)
8+import Yoga.React.DOM.HTML (div)
9+import Yoga.React.DOM.Internal (text)
10+import YogaStories.Story (story)
11+
12+mkLink :: { label :: String, href :: String } -> JSX
13+mkLink = component "LinkStory" \props -> React.do
14+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg flex items-center gap-4" }
15+ [ Link.link { href: props.href, target: "_blank" } (text props.label) ]
16+
17+basic :: JSX
18+basic = story "basic" mkLink { label: "Visit HeroUI", href: "https://heroui.com" }
test/HeroUI/ListBox/Stories.pursnew file+24
@@ -0,0 +1,24 @@
1+module HeroUI.ListBox.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.ListBox as ListBox
7+import HeroUI.Types as T
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkListBox :: {} -> JSX
14+mkListBox = component "ListBoxStory" \(_ :: {}) -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-56" }
16+ [ ListBox.listBox { selectionMode: T.Multiple, defaultSelectedKeys: [ "a" ] }
17+ [ ListBox.listBoxItem { id: "a" } (text "Apple")
18+ , ListBox.listBoxItem { id: "b" } (text "Banana")
19+ , ListBox.listBoxItem { id: "c" } (text "Cherry")
20+ ]
21+ ]
22+
23+basic :: JSX
24+basic = story "basic" mkListBox {}
test/HeroUI/Menu/Stories.pursnew file+24
@@ -0,0 +1,24 @@
1+module HeroUI.Menu.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Menu as Menu
7+import HeroUI.Types as T
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkMenu :: {} -> JSX
14+mkMenu = component "MenuStory" \(_ :: {}) -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-56" }
16+ [ Menu.menu { selectionMode: T.Single, defaultSelectedKeys: [ "profile" ] }
17+ [ Menu.menuItem { id: "profile" } (text "Profile")
18+ , Menu.menuItem { id: "settings" } (text "Settings")
19+ , Menu.menuItem { id: "logout" } (text "Log out")
20+ ]
21+ ]
22+
23+basic :: JSX
24+basic = story "basic" mkMenu {}
test/HeroUI/Modal/Stories.pursnew file+31
@@ -0,0 +1,31 @@
1+module HeroUI.Modal.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Button as Btn
7+import HeroUI.Modal as Modal
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkModal :: { title :: String } -> JSX
14+mkModal = component "ModalStory" \props -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
16+ [ Modal.modal {}
17+ [ Btn.button { variant: Btn.Primary } (text "Open modal")
18+ , Modal.modalBackdrop { variant: Modal.Blur }
19+ [ Modal.modalContainer { placement: Modal.PlacementCenter, size: Modal.Md }
20+ [ Modal.modalDialog {}
21+ [ Modal.modalHeader {} [ Modal.modalHeading {} (text props.title) ]
22+ , Modal.modalBody {} (text "Modal body content.")
23+ , Modal.modalFooter {} [ Modal.modalCloseTrigger {} (text "Close") ]
24+ ]
25+ ]
26+ ]
27+ ]
28+ ]
29+
30+basic :: JSX
31+basic = story "basic" mkModal { title: "Dialog" }
test/HeroUI/NumberField/Stories.pursnew file+25
@@ -0,0 +1,25 @@
1+module HeroUI.NumberField.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.NumberField as NumberField
7+import Yoga.React (component)
8+import Yoga.React.DOM.HTML (div)
9+import Yoga.React.DOM.Internal (text)
10+import YogaStories.Story (story)
11+
12+mkNumberField :: { defaultValue :: Number } -> JSX
13+mkNumberField = component "NumberFieldStory" \props -> React.do
14+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-60" }
15+ [ NumberField.numberField { defaultValue: props.defaultValue, minValue: 0.0, maxValue: 100.0, step: 1.0 }
16+ [ NumberField.numberFieldGroup {}
17+ [ NumberField.numberFieldDecrementButton {} (text "−")
18+ , NumberField.numberFieldInput {} ([] :: Array JSX)
19+ , NumberField.numberFieldIncrementButton {} (text "+")
20+ ]
21+ ]
22+ ]
23+
24+basic :: JSX
25+basic = story "basic" mkNumberField { defaultValue: 5.0 }
test/HeroUI/Pagination/Stories.pursnew file+28
@@ -0,0 +1,28 @@
1+module HeroUI.Pagination.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Pagination as Pagination
7+import HeroUI.Types as T
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkPagination :: {} -> JSX
14+mkPagination = component "PaginationStory" \(_ :: {}) -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
16+ [ Pagination.pagination { size: T.Md }
17+ [ Pagination.paginationContent {}
18+ [ Pagination.paginationPrevious {} (text "‹")
19+ , Pagination.paginationItem { isActive: true } (text "1")
20+ , Pagination.paginationItem { isActive: false } (text "2")
21+ , Pagination.paginationItem { isActive: false } (text "3")
22+ , Pagination.paginationNext {} (text "›")
23+ ]
24+ ]
25+ ]
26+
27+basic :: JSX
28+basic = story "basic" mkPagination {}
test/HeroUI/Popover/Stories.pursnew file+26
@@ -0,0 +1,26 @@
1+module HeroUI.Popover.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Button as Btn
7+import HeroUI.Popover as Popover
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkPopover :: {} -> JSX
14+mkPopover = component "PopoverStory" \(_ :: {}) -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
16+ [ Popover.popover {}
17+ [ Popover.popoverTrigger {} [ Btn.button { variant: Btn.Primary } (text "Open popover") ]
18+ , Popover.popoverContent { placement: "bottom", showArrow: true }
19+ [ Popover.popoverHeading {} (text "Heading")
20+ , text "Popover content."
21+ ]
22+ ]
23+ ]
24+
25+basic :: JSX
26+basic = story "basic" mkPopover {}
test/HeroUI/Progress/Stories.pursnew file+20
@@ -0,0 +1,20 @@
1+module HeroUI.Progress.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Progress as Progress
7+import HeroUI.Types as T
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import YogaStories.Story (story)
11+
12+mkProgress :: { value :: Number } -> JSX
13+mkProgress = component "ProgressStory" \props -> React.do
14+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg flex flex-col gap-4 w-72" }
15+ [ Progress.progressBar { value: props.value, minValue: 0.0, maxValue: 100.0, color: T.Accent, size: T.Md } ([] :: Array JSX)
16+ , Progress.progressCircle { value: props.value, minValue: 0.0, maxValue: 100.0, color: T.Success, size: T.Lg } ([] :: Array JSX)
17+ ]
18+
19+basic :: JSX
20+basic = story "basic" mkProgress { value: 60.0 }
test/HeroUI/Radio/Stories.pursnew file+24
@@ -0,0 +1,24 @@
1+module HeroUI.Radio.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Radio as Radio
7+import HeroUI.Types as T
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkRadio :: { defaultValue :: String } -> JSX
14+mkRadio = component "RadioStory" \props -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
16+ [ Radio.radioGroup { defaultValue: props.defaultValue, orientation: T.Vertical, variant: T.Primary }
17+ [ Radio.radio { value: "a" } (text "Option A")
18+ , Radio.radio { value: "b" } (text "Option B")
19+ , Radio.radio { value: "c" } (text "Option C")
20+ ]
21+ ]
22+
23+basic :: JSX
24+basic = story "basic" mkRadio { defaultValue: "a" }
test/HeroUI/ScrollShadow/Stories.pursnew file+22
@@ -0,0 +1,22 @@
1+module HeroUI.ScrollShadow.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import Data.Array (replicate)
6+import React.Basic (JSX)
7+import HeroUI.ScrollShadow as ScrollShadow
8+import HeroUI.Types as T
9+import Yoga.React (component)
10+import Yoga.React.DOM.HTML (div)
11+import Yoga.React.DOM.Internal (text)
12+import YogaStories.Story (story)
13+
14+mkScrollShadow :: {} -> JSX
15+mkScrollShadow = component "ScrollShadowStory" \(_ :: {}) -> React.do
16+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
17+ [ ScrollShadow.scrollShadow { orientation: T.Vertical, className: "h-40 w-64" }
18+ (replicate 20 (div { className: "py-1" } [ text "Scrollable line" ]))
19+ ]
20+
21+basic :: JSX
22+basic = story "basic" mkScrollShadow {}
test/HeroUI/Select/Stories.pursnew file+29
@@ -0,0 +1,29 @@
1+module HeroUI.Select.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.ListBox as ListBox
7+import HeroUI.Select as Select
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkSelect :: { placeholder :: String } -> JSX
14+mkSelect = component "SelectStory" \props -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-64" }
16+ [ Select.select { placeholder: props.placeholder, defaultSelectedKey: "apple" }
17+ [ Select.selectTrigger {} [ Select.selectValue { placeholder: props.placeholder } ([] :: Array JSX) ]
18+ , Select.selectPopover {}
19+ [ ListBox.listBox {}
20+ [ ListBox.listBoxItem { id: "apple" } (text "Apple")
21+ , ListBox.listBoxItem { id: "banana" } (text "Banana")
22+ , ListBox.listBoxItem { id: "cherry" } (text "Cherry")
23+ ]
24+ ]
25+ ]
26+ ]
27+
28+basic :: JSX
29+basic = story "basic" mkSelect { placeholder: "Pick a fruit" }
test/HeroUI/Separator/Stories.pursnew file+22
@@ -0,0 +1,22 @@
1+module HeroUI.Separator.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Separator as Separator
7+import HeroUI.Types as T
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkSeparator :: {} -> JSX
14+mkSeparator = component "SeparatorStory" \(_ :: {}) -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg flex flex-col gap-3 w-64" }
16+ [ text "Above"
17+ , Separator.separator { orientation: T.Horizontal, variant: Separator.Default } ([] :: Array JSX)
18+ , text "Below"
19+ ]
20+
21+basic :: JSX
22+basic = story "basic" mkSeparator {}
test/HeroUI/Skeleton/Stories.pursnew file+31
@@ -0,0 +1,31 @@
1+module HeroUI.Skeleton.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import Data.Generic.Rep (class Generic)
6+import React.Basic (JSX)
7+import HeroUI.Skeleton as Skeleton
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import YogaStories.Controls (enum)
11+import YogaStories.Story (story)
12+
13+data Animation = None | Pulse | Shimmer
14+
15+derive instance Generic Animation _
16+
17+toAnimation :: Animation -> Skeleton.AnimationType
18+toAnimation = case _ of
19+ None -> Skeleton.None
20+ Pulse -> Skeleton.Pulse
21+ Shimmer -> Skeleton.Shimmer
22+
23+mkSkeleton :: { animation :: Animation } -> JSX
24+mkSkeleton = component "SkeletonStory" \props -> React.do
25+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg flex flex-col gap-3 w-64" }
26+ [ Skeleton.skeleton { animationType: toAnimation props.animation, className: "h-4 w-full rounded" } ([] :: Array JSX)
27+ , Skeleton.skeleton { animationType: toAnimation props.animation, className: "h-4 w-3/4 rounded" } ([] :: Array JSX)
28+ ]
29+
30+basic :: JSX
31+basic = story "basic" mkSkeleton { animation: enum Pulse }
test/HeroUI/Slider/Stories.pursnew file+24
@@ -0,0 +1,24 @@
1+module HeroUI.Slider.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Slider as Slider
7+import HeroUI.Types as T
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import YogaStories.Story (story)
11+
12+mkSlider :: { defaultValue :: Number } -> JSX
13+mkSlider = component "SliderStory" \props -> React.do
14+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-72" }
15+ [ Slider.slider { defaultValue: props.defaultValue, minValue: 0.0, maxValue: 100.0, step: 1.0, orientation: T.Horizontal }
16+ [ Slider.sliderTrack {}
17+ [ Slider.sliderFill {} ([] :: Array JSX)
18+ , Slider.sliderThumb {} ([] :: Array JSX)
19+ ]
20+ ]
21+ ]
22+
23+basic :: JSX
24+basic = story "basic" mkSlider { defaultValue: 40.0 }
test/HeroUI/Spinner/Stories.pursnew file+31
@@ -0,0 +1,31 @@
1+module HeroUI.Spinner.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import Data.Generic.Rep (class Generic)
6+import React.Basic (JSX)
7+import HeroUI.Spinner as Spinner
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import YogaStories.Controls (enum)
11+import YogaStories.Story (story)
12+
13+data Color = Accent | Current | Success | Warning | Danger
14+
15+derive instance Generic Color _
16+
17+toColor :: Color -> Spinner.Color
18+toColor = case _ of
19+ Accent -> Spinner.Accent
20+ Current -> Spinner.Current
21+ Success -> Spinner.Success
22+ Warning -> Spinner.Warning
23+ Danger -> Spinner.Danger
24+
25+mkSpinner :: { color :: Color } -> JSX
26+mkSpinner = component "SpinnerStory" \props -> React.do
27+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg flex items-center gap-4" }
28+ [ Spinner.spinner { color: toColor props.color, size: Spinner.Lg } ([] :: Array JSX) ]
29+
30+basic :: JSX
31+basic = story "basic" mkSpinner { color: enum Accent }
test/HeroUI/Switch/Stories.pursnew file+19
@@ -0,0 +1,19 @@
1+module HeroUI.Switch.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Switch as Switch
7+import HeroUI.Types as T
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkSwitch :: { label :: String, defaultSelected :: Boolean } -> JSX
14+mkSwitch = component "SwitchStory" \props -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
16+ [ Switch.switch_ { defaultSelected: props.defaultSelected, size: T.Md } (text props.label) ]
17+
18+basic :: JSX
19+basic = story "basic" mkSwitch { label: "Wi-Fi", defaultSelected: true }
test/HeroUI/Table/Stories.pursnew file+38
@@ -0,0 +1,38 @@
1+module HeroUI.Table.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Table as Table
7+import HeroUI.Types as T
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+row :: String -> String -> String -> JSX
14+row key name role =
15+ Table.tableRow { id: key }
16+ [ Table.tableCell {} (text name)
17+ , Table.tableCell {} (text role)
18+ ]
19+
20+mkTable :: {} -> JSX
21+mkTable = component "TableStory" \(_ :: {}) -> React.do
22+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
23+ [ Table.table {}
24+ [ Table.tableContent { selectionMode: T.Multiple, "aria-label": "People" }
25+ [ Table.tableHeader {}
26+ [ Table.tableColumn { id: "name", isRowHeader: true } (text "Name")
27+ , Table.tableColumn { id: "role" } (text "Role")
28+ ]
29+ , Table.tableBody {}
30+ [ row "1" "Alice" "Admin"
31+ , row "2" "Bob" "User"
32+ ]
33+ ]
34+ ]
35+ ]
36+
37+basic :: JSX
38+basic = story "basic" mkTable {}
test/HeroUI/Tabs/Stories.pursnew file+37
@@ -0,0 +1,37 @@
1+module HeroUI.Tabs.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import Data.Generic.Rep (class Generic)
6+import React.Basic (JSX)
7+import HeroUI.Tabs as Tabs
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Controls (enum)
12+import YogaStories.Story (story)
13+
14+data Variant = Primary | Secondary
15+
16+derive instance Generic Variant _
17+
18+toVariant :: Variant -> Tabs.Variant
19+toVariant = case _ of
20+ Primary -> Tabs.Primary
21+ Secondary -> Tabs.Secondary
22+
23+mkTabs :: { variant :: Variant } -> JSX
24+mkTabs = component "TabsStory" \props -> React.do
25+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg w-96" }
26+ [ Tabs.tabs { variant: toVariant props.variant, defaultSelectedKey: "photos" }
27+ [ Tabs.tabList {}
28+ [ Tabs.tab { id: "photos" } (text "Photos")
29+ , Tabs.tab { id: "music" } (text "Music")
30+ ]
31+ , Tabs.tabPanel { id: "photos" } (text "Photos panel")
32+ , Tabs.tabPanel { id: "music" } (text "Music panel")
33+ ]
34+ ]
35+
36+basic :: JSX
37+basic = story "basic" mkTabs { variant: enum Primary }
test/HeroUI/Toast/Stories.pursnew file+23
@@ -0,0 +1,23 @@
1+module HeroUI.Toast.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import React.Basic.Events (handler_)
7+import HeroUI.Button as Btn
8+import HeroUI.Toast as Toast
9+import Yoga.React (component)
10+import Yoga.React.DOM.HTML (div)
11+import Yoga.React.DOM.Internal (text)
12+import YogaStories.Story (story)
13+
14+mkToast :: { message :: String } -> JSX
15+mkToast = component "ToastStory" \props -> React.do
16+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
17+ [ Toast.toastProvider { placement: "bottom-right" } ([] :: Array JSX)
18+ , Btn.button { variant: Btn.Primary, onPress: handler_ (void (Toast.toastSuccess (text props.message))) }
19+ (text "Show toast")
20+ ]
21+
22+basic :: JSX
23+basic = story "basic" mkToast { message: "Saved!" }
test/HeroUI/Tooltip/Stories.pursnew file+23
@@ -0,0 +1,23 @@
1+module HeroUI.Tooltip.Stories (basic) where
2+
3+import Prelude hiding (div)
4+
5+import React.Basic (JSX)
6+import HeroUI.Button as Btn
7+import HeroUI.Tooltip as Tooltip
8+import Yoga.React (component)
9+import Yoga.React.DOM.HTML (div)
10+import Yoga.React.DOM.Internal (text)
11+import YogaStories.Story (story)
12+
13+mkTooltip :: { tip :: String } -> JSX
14+mkTooltip = component "TooltipStory" \props -> React.do
15+ pure $ div { className: "dark bg-background text-foreground p-6 rounded-lg" }
16+ [ Tooltip.tooltip {}
17+ [ Tooltip.tooltipTrigger {} [ Btn.button { variant: Btn.Primary } (text "Hover me") ]
18+ , Tooltip.tooltipContent { placement: "top", showArrow: true } (text props.tip)
19+ ]
20+ ]
21+
22+basic :: JSX
23+basic = story "basic" mkTooltip { tip: "Helpful hint" }