@@ -0,0 +1,127 @@
1+module React.Aria.Combobox where
2+
3+import Prelude
4+
5+import Data.Nullable (Nullable)
6+import Effect (Effect)
7+import Effect.Uncurried (EffectFn1, EffectFn2, runEffectFn2)
8+import Prim.Row (class Union)
9+import React.Aria.JSSet (JSSet)
10+import React.Aria.Types (FocusStrategy, MenuTriggerAction, Selection, SelectionBehaviour, SelectionMode, ValidationState)
11+import React.Basic (JSX)
12+import React.Basic.Events (EventHandler, SyntheticEvent)
13+import React.Basic.Hooks (Hook, Ref, unsafeHook)
14+import Web.DOM (Node)
15+
16+-- UseComboBox
17+newtype UseComboBox hooks = UseComboBox hooks
18+
19+type AriaComboBoxPropsRequired a r =
20+ ( inputRef ∷ Ref (Nullable Node)
21+ , popoverRef ∷ Ref (Nullable Node)
22+ , listBoxRef ∷ Ref (Nullable Node)
23+ , children ∷ a → JSX -- Must map to either an item or a section
24+ | r
25+ )
26+
27+type AriaComboBoxPropsOptional a =
28+ ( buttonRef ∷ Ref (Nullable Node)
29+ , defaultItems ∷ Array a
30+ , items ∷ Array a
31+ -- , keyboardDelegate :: KeyboardDelegate
32+ , onOpenChange ∷
33+ EffectFn2 Boolean {- isOpen -}
34+ String {- menuTriggerAction: 'focus' | 'input' | 'manual' -}
35+ Unit
36+ , inputValue ∷ String
37+ , defaultInputValue ∷ String
38+ , onInputChange ∷ EffectFn1 String Unit
39+ , allowsCustomValue ∷ Boolean
40+ , menuTrigger ∷ MenuTriggerAction
41+ , shouldFocusWrap ∷ Boolean -- | Whether keyboard navigation is circular.
42+ , disabledKeys ∷
43+ Array String -- | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with.
44+ , disallowEmptySelection ∷ Boolean -- | Whether the collection allows empty selection.
45+ , selectedKey ∷ String -- | The currently selected key in the collection (controlled).
46+ , defaultSelectedKey ∷ String -- | The initial selected key in the collection (uncontrolled).
47+ , onSelectionChange ∷ EffectFn1 String Unit
48+ , isDisabled ∷ Boolean
49+ , isReadOnly ∷ Boolean
50+ , placeholder ∷ String
51+ , id ∷ String
52+ , validationState ∷ ValidationState
53+ , isRequired ∷ Boolean
54+ , autoFocus ∷ Boolean
55+ , onFocus ∷ EventHandler
56+ , onBlur ∷ EventHandler
57+ , onFocusChange ∷ EffectFn1 Boolean Unit
58+ , onKeyDown ∷ EventHandler
59+ , onKeyUp ∷ EventHandler
60+ , label ∷ JSX
61+ , description ∷ JSX
62+ , errorMessage ∷ JSX
63+ )
64+
65+type UseComboBoxState =
66+ { inputValue ∷ String
67+ , isFocused ∷ Boolean
68+ , selectedKey ∷ String
69+ , selectedItem ∷ Node
70+ , collection ∷ Array Node
71+ , disabledKeys :: JSSet String
72+ , selectionManager :: SelectionManager
73+ , focusStrategy ∷ FocusStrategy
74+ , isOpen ∷ Boolean
75+ , setInputValue ∷ EffectFn1 String Unit
76+ , commit ∷ Effect Unit
77+ , open ∷ EffectFn2 (Nullable FocusStrategy) MenuTriggerAction Unit
78+ , toggle ∷ EffectFn2 (Nullable FocusStrategy) MenuTriggerAction Unit
79+ , revert ∷ Effect Unit
80+ , setFocused ∷ EffectFn1 Boolean Unit
81+ , setSelectedKey ∷ EffectFn1 String Unit
82+ , close ∷ Effect Unit
83+ }
84+
85+type SelectionManager =
86+ { selectionMode ∷ SelectionMode
87+ , disallowEmptySelection ∷ Boolean
88+ , selectionBehavior ∷ SelectionBehaviour
89+ , isFocused ∷ Boolean
90+ , focusedKey ∷ String
91+ , childFocusStrategy ∷ FocusStrategy
92+ , selectedKeys :: JSSet String
93+ , rawSelection :: Selection
94+ , isEmpty ∷ Boolean
95+ , isSelectAll ∷ Boolean
96+ , firstSelectedKey ∷ Nullable String
97+ , lastSelectedKey ∷ Nullable String
98+ , setSelectionBehavior ∷ EffectFn1 SelectionBehaviour Unit
99+ , setFocused ∷ EffectFn1 Boolean Unit
100+ , setFocusedKey ∷ EffectFn2 String FocusStrategy Unit
101+ , isSelected ∷ EffectFn1 String Boolean
102+ , extendSelection ∷ EffectFn1 String Unit
103+ , toggleSelection ∷ EffectFn1 String Unit
104+ , replaceSelection ∷ EffectFn1 String Unit
105+ , setSelectedKeys ∷ EffectFn1 (Array String) Unit
106+ , selectAll ∷ Effect Unit
107+ , clearSelection ∷ Effect Unit
108+ , toggleSelectAll ∷ Effect Unit
109+ , select ∷ EffectFn2 String SyntheticEvent Unit
110+ , isSelectionEqual :: EffectFn1 (JSSet String) Unit
111+ , canSelectItem ∷ EffectFn1 String Unit
112+ }
113+
114+type ComboBoxAria = { comboBoxProps ∷ { "data-isComboBox" ∷ Boolean } }
115+
116+foreign import useComboBoxImpl
117+ ∷ ∀ props state
118+ . EffectFn2 props state ComboBoxAria
119+
120+useComboBox
121+ ∷ ∀ a props props_
122+ . Union props props_ (AriaComboBoxPropsOptional a)
123+ ⇒ { | AriaComboBoxPropsRequired a props }
124+ → UseComboBoxState
125+ → Hook UseComboBox ComboBoxAria
126+useComboBox p s = unsafeHook do
127+ runEffectFn2 useComboBoxImpl p s