@@ -2,8 +2,8 @@ import { ariaAttr, dataAttr, getEventKey, isComposingEvent } from "@zag-js/dom-q
22import { getPlacementStyles } from "@zag-js/popper"
33import type { EventKeyMap , NormalizeProps , PropTypes } from "@zag-js/types"
44import { parts } from "./time-picker.anatomy"
5- import { dom } from "./time-picker.dom"
6- import type { MachineApi , Send , State } from "./time-picker.types"
5+ import * as dom from "./time-picker.dom"
6+ import type { TimePickerApi , TimePickerService } from "./time-picker.types"
77import {
88 get12HourFormatPeriodHour ,
99 getHourPeriod ,
@@ -12,28 +12,34 @@ import {
1212 padStart ,
1313} from "./time-picker.utils"
1414
15- export function connect < T extends PropTypes > ( state : State , send : Send , normalize : NormalizeProps < T > ) : MachineApi < T > {
16- const disabled = state . context . disabled
17- const readOnly = state . context . readOnly
15+ export function connect < T extends PropTypes > (
16+ service : TimePickerService ,
17+ normalize : NormalizeProps < T > ,
18+ ) : TimePickerApi < T > {
19+ const { state, send, prop, computed, scope, context } = service
1820
19- const locale = state . context . locale
21+ const disabled = prop ( "disabled" )
22+ const readOnly = prop ( "readOnly" )
23+
24+ const locale = prop ( "locale" )
2025 const hour12 = is12HourFormat ( locale )
2126
22- const min = state . context . min
23- const max = state . context . max
24- const steps = state . context . steps
27+ const min = prop ( " min" )
28+ const max = prop ( " max" )
29+ const steps = prop ( " steps" )
2530
2631 const focused = state . matches ( "focused" )
2732 const open = state . hasTag ( "open" )
2833
29- const value = state . context . value
30- const valueAsString = state . context . valueAsString
31- const currentTime = state . context . currentTime
34+ const value = context . get ( "value" )
35+ const valueAsString = computed ( "valueAsString" )
36+ const currentTime = context . get ( "currentTime" )
37+ const focusedColumn = context . get ( "focusedColumn" )
3238
33- const currentPlacement = state . context . currentPlacement
39+ const currentPlacement = context . get ( " currentPlacement" )
3440 const popperStyles = getPlacementStyles ( {
35- ...state . context . positioning ,
36- placement : state . context . currentPlacement ,
41+ ...prop ( " positioning" ) ,
42+ placement : currentPlacement ,
3743 } )
3844
3945 return {
@@ -47,7 +53,7 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
4753 } ,
4854 setOpen ( nextOpen ) {
4955 if ( nextOpen === open ) return
50- send ( nextOpen ? "OPEN" : "CLOSE" )
56+ send ( { type : nextOpen ? "OPEN" : "CLOSE" } )
5157 } ,
5258 setUnitValue ( unit , value ) {
5359 send ( { type : "UNIT.SET" , unit, value } )
@@ -56,7 +62,7 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
5662 send ( { type : "VALUE.SET" , value } )
5763 } ,
5864 clearValue ( ) {
59- send ( "VALUE.CLEAR" )
65+ send ( { type : "VALUE.CLEAR" } )
6066 } ,
6167 getHours ( ) {
6268 const length = hour12 ? 12 : 24
@@ -90,8 +96,8 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
9096 getLabelProps ( ) {
9197 return normalize . label ( {
9298 ...parts . label . attrs ,
93- dir : state . context . dir ,
94- htmlFor : dom . getInputId ( state . context ) ,
99+ dir : prop ( " dir" ) ,
100+ htmlFor : dom . getInputId ( scope ) ,
95101 "data-state" : open ? "open" : "closed" ,
96102 "data-disabled" : dataAttr ( disabled ) ,
97103 "data-readonly" : dataAttr ( readOnly ) ,
@@ -101,27 +107,27 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
101107 getControlProps ( ) {
102108 return normalize . element ( {
103109 ...parts . control . attrs ,
104- dir : state . context . dir ,
105- id : dom . getControlId ( state . context ) ,
110+ dir : prop ( " dir" ) ,
111+ id : dom . getControlId ( scope ) ,
106112 "data-disabled" : dataAttr ( disabled ) ,
107113 } )
108114 } ,
109115
110116 getInputProps ( ) {
111117 return normalize . input ( {
112118 ...parts . input . attrs ,
113- dir : state . context . dir ,
119+ dir : prop ( " dir" ) ,
114120 autoComplete : "off" ,
115121 autoCorrect : "off" ,
116122 spellCheck : "false" ,
117- id : dom . getInputId ( state . context ) ,
118- name : state . context . name ,
123+ id : dom . getInputId ( scope ) ,
124+ name : prop ( " name" ) ,
119125 defaultValue : valueAsString ,
120- placeholder : getInputPlaceholder ( state . context ) ,
126+ placeholder : getInputPlaceholder ( prop ( "placeholder" ) , prop ( "allowSeconds" ) , locale ) ,
121127 disabled,
122128 readOnly,
123129 onFocus ( ) {
124- send ( "INPUT.FOCUS" )
130+ send ( { type : "INPUT.FOCUS" } )
125131 } ,
126132 onBlur ( event ) {
127133 send ( { type : "INPUT.BLUR" , value : event . currentTarget . value } )
@@ -138,42 +144,42 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
138144 getTriggerProps ( ) {
139145 return normalize . button ( {
140146 ...parts . trigger . attrs ,
141- id : dom . getTriggerId ( state . context ) ,
147+ id : dom . getTriggerId ( scope ) ,
142148 type : "button" ,
143- "data-placement" : state . context . currentPlacement ,
149+ "data-placement" : currentPlacement ,
144150 disabled,
145151 "data-readonly" : dataAttr ( readOnly ) ,
146152 "aria-label" : open ? "Close calendar" : "Open calendar" ,
147- "aria-controls" : dom . getContentId ( state . context ) ,
153+ "aria-controls" : dom . getContentId ( scope ) ,
148154 "data-state" : open ? "open" : "closed" ,
149155 onClick ( event ) {
150156 if ( event . defaultPrevented ) return
151- send ( "TRIGGER.CLICK" )
157+ send ( { type : "TRIGGER.CLICK" } )
152158 } ,
153159 } )
154160 } ,
155161
156162 getClearTriggerProps ( ) {
157163 return normalize . button ( {
158164 ...parts . clearTrigger . attrs ,
159- id : dom . getClearTriggerId ( state . context ) ,
165+ id : dom . getClearTriggerId ( scope ) ,
160166 type : "button" ,
161- hidden : ! state . context . value ,
167+ hidden : ! value ,
162168 disabled,
163169 "data-readonly" : dataAttr ( readOnly ) ,
164170 "aria-label" : "Clear time" ,
165171 onClick ( event ) {
166172 if ( event . defaultPrevented ) return
167- send ( "VALUE.CLEAR" )
173+ send ( { type : "VALUE.CLEAR" } )
168174 } ,
169175 } )
170176 } ,
171177
172178 getPositionerProps ( ) {
173179 return normalize . element ( {
174180 ...parts . positioner . attrs ,
175- dir : state . context . dir ,
176- id : dom . getPositionerId ( state . context ) ,
181+ dir : prop ( " dir" ) ,
182+ id : dom . getPositionerId ( scope ) ,
177183 style : popperStyles . floating ,
178184 } )
179185 } ,
@@ -187,8 +193,8 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
187193 getContentProps ( ) {
188194 return normalize . element ( {
189195 ...parts . content . attrs ,
190- dir : state . context . dir ,
191- id : dom . getContentId ( state . context ) ,
196+ dir : prop ( " dir" ) ,
197+ id : dom . getContentId ( scope ) ,
192198 hidden : ! open ,
193199 tabIndex : 0 ,
194200 role : "application" ,
@@ -219,12 +225,12 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
219225 // prevent tabbing out of the time picker
220226 Tab ( ) { } ,
221227 Escape ( ) {
222- if ( ! state . context . disableLayer ) return
228+ if ( ! prop ( " disableLayer" ) ) return
223229 send ( { type : "CONTENT.ESCAPE" } )
224230 } ,
225231 }
226232
227- const exec = keyMap [ getEventKey ( event , state . context ) ]
233+ const exec = keyMap [ getEventKey ( event , { dir : prop ( "dir" ) } ) ]
228234
229235 if ( exec ) {
230236 exec ( event )
@@ -235,24 +241,24 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
235241 } ,
236242
237243 getColumnProps ( props ) {
238- const hidden = ( props . unit === "second" && ! state . context . allowSeconds ) || ( props . unit === "period" && ! hour12 )
244+ const hidden = ( props . unit === "second" && ! prop ( " allowSeconds" ) ) || ( props . unit === "period" && ! hour12 )
239245 return normalize . element ( {
240246 ...parts . column . attrs ,
241- id : dom . getColumnId ( state . context , props . unit ) ,
247+ id : dom . getColumnId ( scope , props . unit ) ,
242248 "data-unit" : props . unit ,
243- "data-focus" : dataAttr ( state . context . focusedColumn === props . unit ) ,
249+ "data-focus" : dataAttr ( focusedColumn === props . unit ) ,
244250 hidden,
245251 } )
246252 } ,
247253
248254 getHourCellProps ( props ) {
249255 const hour = props . value
250256 const isSelectable = ! (
251- ( min && get12HourFormatPeriodHour ( hour , state . context . period ) < min . hour ) ||
252- ( max && get12HourFormatPeriodHour ( hour , state . context . period ) > max . hour )
257+ ( min && get12HourFormatPeriodHour ( hour , computed ( " period" ) ) < min . hour ) ||
258+ ( max && get12HourFormatPeriodHour ( hour , computed ( " period" ) ) > max . hour )
253259 )
254- const isSelected = state . context . value ?. hour === get12HourFormatPeriodHour ( hour , state . context . period )
255- const isFocused = state . context . focusedColumn === "hour" && state . context . focusedValue === hour
260+ const isSelected = value ?. hour === get12HourFormatPeriodHour ( hour , computed ( " period" ) )
261+ const isFocused = focusedColumn === "hour" && context . get ( " focusedValue" ) === hour
256262
257263 const currentHour = hour12 && currentTime ? currentTime ?. hour % 12 : currentTime ?. hour
258264 const isCurrent = currentHour === hour || ( hour === 12 && currentHour === 0 )
@@ -279,17 +285,17 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
279285
280286 getMinuteCellProps ( props ) {
281287 const minute = props . value
282- const { value } = state . context
288+ const value = context . get ( "value" )
283289 const minMinute = min ?. set ( { second : 0 } )
284290 const maxMinute = max ?. set ( { second : 0 } )
285291
286292 const isSelectable = ! (
287293 ( minMinute && value && minMinute . compare ( value . set ( { minute } ) ) > 0 ) ||
288294 ( maxMinute && value && maxMinute . compare ( value . set ( { minute } ) ) < 0 )
289295 )
290- const isSelected = state . context . value ?. minute === minute
296+ const isSelected = value ?. minute === minute
291297 const isCurrent = currentTime ?. minute === minute
292- const isFocused = state . context . focusedColumn === "minute" && state . context . focusedValue === minute
298+ const isFocused = focusedColumn === "minute" && context . get ( " focusedValue" ) === minute
293299
294300 return normalize . button ( {
295301 ...parts . cell . attrs ,
@@ -318,9 +324,9 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
318324 ( min && value ?. minute && min . compare ( value . set ( { second } ) ) > 0 ) ||
319325 ( max && value ?. minute && max . compare ( value . set ( { second } ) ) < 0 )
320326 )
321- const isSelected = state . context . value ?. second === second
327+ const isSelected = value ?. second === second
322328 const isCurrent = currentTime ?. second === second
323- const isFocused = state . context . focusedColumn === "second" && state . context . focusedValue === second
329+ const isFocused = focusedColumn === "second" && context . get ( " focusedValue" ) === second
324330
325331 return normalize . button ( {
326332 ...parts . cell . attrs ,
@@ -343,10 +349,10 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
343349 } ,
344350
345351 getPeriodCellProps ( props ) {
346- const isSelected = state . context . period === props . value
347- const currentPeriod = getHourPeriod ( currentTime ?. hour , state . context . locale )
352+ const isSelected = computed ( " period" ) === props . value
353+ const currentPeriod = getHourPeriod ( currentTime ?. hour , locale )
348354 const isCurrent = currentPeriod === props . value
349- const isFocused = state . context . focusedColumn === "period" && state . context . focusedValue === props . value
355+ const isFocused = focusedColumn === "period" && context . get ( " focusedValue" ) === props . value
350356
351357 return normalize . button ( {
352358 ...parts . cell . attrs ,
0 commit comments