git.iko.soy/rowtype-yoga/purescript-yoga-heroui3
on main help sign in
Toast imperative API takes any IsJSX (String | JSX | Array JSX), not just JSX
commitc5a1a2ac035d74d055e254e774108a6295c61bb1 authorMark <mark.eibes@gmail.com> dateSun 31 May 2026, 18:46 (4 months ago) parentebf532a
5 files changed+45−5
src/HeroUI/Autocomplete.purs+26−1 src/HeroUI/Raw.js+2 src/HeroUI/Raw.purs+1 test/HeroUI/Autocomplete/Stories.purs+11−4 yoga-stories-head.js+5
src/HeroUI/Autocomplete.purs+26−1
@@ -6,7 +6,8 @@ import Effect (Effect)
66import Effect.Uncurried (EffectFn1)
77import React.Basic (JSX)
88import Yoga.React.DOM.Internal (class IsJSX)
9−import Data.Function.Uncurried (runFn4)
9+import Data.Function.Uncurried (Fn2, mkFn2, runFn4)
10+import Data.String (Pattern(..), contains, toLower)
1011import HeroUI.Types (FieldVariant, fieldVariantToString)
1112import HeroUI.Internal (class CoerceHeroProps, createElementTransformImpl)
1213import HeroUI.Raw as Raw
@@ -78,6 +79,30 @@ autocompletePopover
7879 -> JSX
7980autocompletePopover props kids = runFn4 createElementTransformImpl {} Raw.autocompletePopover props kids
8081
82+-- | Wraps the search `input` + the options collection inside the popover;
83+-- | this is what makes the autocomplete typeable. Pass `filter` to narrow the
84+-- | options as the user types (see `containsFilter` for the common case).
85+type AutocompleteFilterProps r =
86+ ( filter :: Fn2 String String Boolean
87+ , className :: String
88+ | r
89+ )
90+
91+autocompleteFilter
92+ :: forall givenProps nonDataProps kids
93+ . IsJSX kids
94+ => CoerceHeroProps { | givenProps } { | nonDataProps } { | AutocompleteFilterProps () }
95+ => { | givenProps }
96+ -> kids
97+ -> JSX
98+autocompleteFilter props kids = runFn4 createElementTransformImpl {} Raw.autocompleteFilter props kids
99+
100+-- | Case-insensitive substring match — the usual `filter` for `autocompleteFilter`.
101+-- | react-aria calls it as `filter optionTextValue typedInput`; keep an option
102+-- | when what the user typed appears anywhere in its `textValue`.
103+containsFilter :: Fn2 String String Boolean
104+containsFilter = mkFn2 \optionText typed -> contains (Pattern (toLower typed)) (toLower optionText)
105+
81106autocompleteClearButton
82107 :: forall givenProps nonDataProps kids
83108 . IsJSX kids
src/HeroUI/Raw.js+2
@@ -87,6 +87,7 @@ import {
8787 AutocompleteIndicator,
8888 AutocompletePopover,
8989 AutocompleteClearButton,
90+ AutocompleteFilter,
9091 DateFieldRoot,
9192 TimeFieldRoot,
9293 DatePickerRoot,
@@ -338,6 +339,7 @@ export const autocompleteValue = AutocompleteValue;
338339export const autocompleteIndicator = AutocompleteIndicator;
339340export const autocompletePopover = AutocompletePopover;
340341export const autocompleteClearButton = AutocompleteClearButton;
342+export const autocompleteFilter = AutocompleteFilter;
341343
342344// DateField / TimeField
343345export const dateField = DateFieldRoot;
src/HeroUI/Raw.purs+1
@@ -137,6 +137,7 @@ foreign import autocompleteValue :: forall r. ReactComponent { | r }
137137foreign import autocompleteIndicator :: forall r. ReactComponent { | r }
138138foreign import autocompletePopover :: forall r. ReactComponent { | r }
139139foreign import autocompleteClearButton :: forall r. ReactComponent { | r }
140+foreign import autocompleteFilter :: forall r. ReactComponent { | r }
140141
141142-- DateField / TimeField
142143foreign import dateField :: forall r. ReactComponent { | r }
test/HeroUI/Autocomplete/Stories.purs+11−4
@@ -4,6 +4,7 @@ import Prelude hiding (div)
44
55import React.Basic (JSX)
66import HeroUI.Autocomplete as Autocomplete
7+import HeroUI.Input as Input
78import HeroUI.ListBox as ListBox
89import Yoga.React (component)
910import Yoga.React.DOM.HTML (div)
@@ -18,10 +19,16 @@ mkAutocomplete = component "AutocompleteStory" \props -> React.do
1819 , Autocomplete.autocompleteIndicator {} ([] :: Array JSX)
1920 ]
2021 , Autocomplete.autocompletePopover {}
21− [ ListBox.listBox {}
22− [ ListBox.listBoxItem { id: "apple" } "Apple"
23− , ListBox.listBoxItem { id: "banana" } "Banana"
24− , ListBox.listBoxItem { id: "cherry" } "Cherry"
22+ [ Autocomplete.autocompleteFilter { filter: Autocomplete.containsFilter }
23+ [ Input.textField { "aria-label": "Search fruit" }
24+ [ Input.input { placeholder: "Type to filter…" } ([] :: Array JSX) ]
25+ , ListBox.listBox {}
26+ [ ListBox.listBoxItem { id: "apple", textValue: "Apple" } "Apple"
27+ , ListBox.listBoxItem { id: "banana", textValue: "Banana" } "Banana"
28+ , ListBox.listBoxItem { id: "cherry", textValue: "Cherry" } "Cherry"
29+ , ListBox.listBoxItem { id: "date", textValue: "Date" } "Date"
30+ , ListBox.listBoxItem { id: "elderberry", textValue: "Elderberry" } "Elderberry"
31+ ]
2532 ]
2633 ]
2734 ]
yoga-stories-head.js+5
@@ -1 +1,6 @@
11import "./heroui-styles.css"
2+
3+// HeroUI v3 themes via a `dark` class on an ancestor. Overlays (popover,
4+// modal, dropdown) portal to <body>, outside any per-story wrapper, so set
5+// the class on the document root to keep portaled content on-theme.
6+document.documentElement.classList.add("dark")