@kosdev-code/kos-dispense-sdk 3.0.28 → 3.0.29

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.
Files changed (190) hide show
  1. package/.kos.json +7 -0
  2. package/{dispense-registration-manager-Dtb31fcI.cjs → dispense-registration-manager-CfWgJqfq.cjs} +590 -172
  3. package/dispense-registration-manager-CfWgJqfq.cjs.map +1 -0
  4. package/{dispense-registration-manager-Da9CW_cN.js → dispense-registration-manager-DtN0T_JG.js} +623 -205
  5. package/dispense-registration-manager-DtN0T_JG.js.map +1 -0
  6. package/{extension-utils-Cfhe358W.cjs → extension-utils-BWYG2dYG.cjs} +2 -2
  7. package/extension-utils-BWYG2dYG.cjs.map +1 -0
  8. package/{extension-utils-D_dnBLH6.js → extension-utils-BoXtjU5_.js} +2 -2
  9. package/extension-utils-BoXtjU5_.js.map +1 -0
  10. package/index.cjs +7 -5
  11. package/index.cjs.map +1 -1
  12. package/index.js +67 -65
  13. package/index.js.map +1 -1
  14. package/models/models/assembly/assembly-model.d.ts +8 -0
  15. package/models/models/assembly/assembly-model.d.ts.map +1 -1
  16. package/models/models/assembly/assembly-registration.d.ts +2 -0
  17. package/models/models/assembly/assembly-registration.d.ts.map +1 -1
  18. package/models/models/assembly/board-utils.d.ts.map +1 -1
  19. package/models/models/assembly/nozzle-utils.d.ts.map +1 -1
  20. package/models/models/assembly/pump-utils.d.ts.map +1 -1
  21. package/models/models/assembly/services/assembly-services.d.ts.map +1 -1
  22. package/models/models/assembly/types/index.d.ts +6 -0
  23. package/models/models/availability/availability-model.d.ts +2 -0
  24. package/models/models/availability/availability-model.d.ts.map +1 -1
  25. package/models/models/availability/types/index.d.ts +4 -0
  26. package/models/models/board/board-container-model.d.ts +8 -0
  27. package/models/models/board/board-container-model.d.ts.map +1 -1
  28. package/models/models/board/board-container-registration.d.ts +2 -0
  29. package/models/models/board/board-container-registration.d.ts.map +1 -1
  30. package/models/models/board/board-registration.d.ts +2 -0
  31. package/models/models/board/board-registration.d.ts.map +1 -1
  32. package/models/models/board/types/index.d.ts +12 -0
  33. package/models/models/cui-kit-state/cui-kit-state-model.d.ts +133 -0
  34. package/models/models/cui-kit-state/cui-kit-state-model.d.ts.map +1 -0
  35. package/models/models/cui-kit-state/index.d.ts +4 -0
  36. package/models/models/cui-kit-state/index.d.ts.map +1 -0
  37. package/models/models/cui-kit-state/types/index.d.ts +82 -0
  38. package/models/models/device-assembly/device-assembly-model.d.ts +4 -0
  39. package/models/models/device-assembly/device-assembly-model.d.ts.map +1 -1
  40. package/models/models/device-assembly/device-assembly-registration.d.ts +2 -0
  41. package/models/models/device-assembly/device-assembly-registration.d.ts.map +1 -1
  42. package/models/models/device-assembly/types/index.d.ts +4 -0
  43. package/models/models/generic-pour/generic-pour-model.d.ts +16 -0
  44. package/models/models/generic-pour/generic-pour-model.d.ts.map +1 -1
  45. package/models/models/generic-pour/generic-pour-registration.d.ts +2 -0
  46. package/models/models/generic-pour/generic-pour-registration.d.ts.map +1 -1
  47. package/models/models/generic-pour/types/index.d.ts +4 -0
  48. package/models/models/holder/holder-model.d.ts +6 -0
  49. package/models/models/holder/holder-model.d.ts.map +1 -1
  50. package/models/models/holder/services/holder-services.d.ts.map +1 -1
  51. package/models/models/holder/types/index.d.ts +6 -0
  52. package/models/models/holder-container/holder-container-model.d.ts +2 -0
  53. package/models/models/holder-container/holder-container-model.d.ts.map +1 -1
  54. package/models/models/holder-container/types/index.d.ts +14 -0
  55. package/models/models/index.d.ts +1 -0
  56. package/models/models/index.d.ts.map +1 -1
  57. package/models/models/ingredient/ingredient-model.d.ts +2 -0
  58. package/models/models/ingredient/ingredient-model.d.ts.map +1 -1
  59. package/models/models/ingredient/types/index.d.ts +4 -1
  60. package/models/models/ingredient-container/ingredient-container-model.d.ts +2 -0
  61. package/models/models/ingredient-container/ingredient-container-model.d.ts.map +1 -1
  62. package/models/models/ingredient-container/types/index.d.ts +6 -0
  63. package/models/models/nozzle/nozzle-model.d.ts +4 -2
  64. package/models/models/nozzle/nozzle-model.d.ts.map +1 -1
  65. package/models/models/nozzle/types/index.d.ts +6 -0
  66. package/models/models/pump/pump-model.d.ts +2 -0
  67. package/models/models/pump/pump-model.d.ts.map +1 -1
  68. package/models/models/pump/types/index.d.ts +6 -0
  69. package/models/models/pump-container/pump-container-model.d.ts +6 -0
  70. package/models/models/pump-container/pump-container-model.d.ts.map +1 -1
  71. package/models/models/pump-container/types/index.d.ts +6 -0
  72. package/models/utils/dispense-registration-manager.d.ts +29 -4
  73. package/models/utils/dispense-registration-manager.d.ts.map +1 -1
  74. package/models/utils/extension-utils.d.ts +22 -0
  75. package/models/utils/extension-utils.d.ts.map +1 -1
  76. package/models/utils/pour-context.d.ts +8 -0
  77. package/models/utils/pour-context.d.ts.map +1 -0
  78. package/models/utils/service.d.ts +1 -1
  79. package/models/utils/services/dispense/1.6.5/service.d.ts +1 -1
  80. package/models/utils/services/dispense/1.8.1/service.d.ts +1 -1
  81. package/models/utils/services/dispense/daily/service.d.ts +1 -1
  82. package/models.cjs +4 -2
  83. package/models.cjs.map +1 -1
  84. package/models.js +17 -15
  85. package/package.json +2 -2
  86. package/{pump-provider-uNNMh9uh.cjs → pump-provider-B4WR3LiY.cjs} +402 -443
  87. package/pump-provider-B4WR3LiY.cjs.map +1 -0
  88. package/{pump-provider-BQmCKz7S.js → pump-provider-CPUsLke5.js} +448 -489
  89. package/pump-provider-CPUsLke5.js.map +1 -0
  90. package/ui/contexts/assembly/assembly-provider.d.ts +8 -0
  91. package/ui/contexts/assembly/assembly-provider.d.ts.map +1 -1
  92. package/ui/contexts/availability/availability-provider.d.ts +8 -0
  93. package/ui/contexts/availability/availability-provider.d.ts.map +1 -1
  94. package/ui/contexts/board/board-provider.d.ts +8 -0
  95. package/ui/contexts/board/board-provider.d.ts.map +1 -1
  96. package/ui/contexts/board-container/board-container-provider.d.ts +8 -0
  97. package/ui/contexts/board-container/board-container-provider.d.ts.map +1 -1
  98. package/ui/contexts/cui-kit/cui-kit.d.ts +16 -1
  99. package/ui/contexts/cui-kit/cui-kit.d.ts.map +1 -1
  100. package/ui/contexts/device-assembly/device-assembly-provider.d.ts +8 -0
  101. package/ui/contexts/device-assembly/device-assembly-provider.d.ts.map +1 -1
  102. package/ui/contexts/holder/holder-provider.d.ts +8 -0
  103. package/ui/contexts/holder/holder-provider.d.ts.map +1 -1
  104. package/ui/contexts/holder-container/holder-container-provider.d.ts +8 -0
  105. package/ui/contexts/holder-container/holder-container-provider.d.ts.map +1 -1
  106. package/ui/contexts/ingredient/ingredient-provider.d.ts +8 -0
  107. package/ui/contexts/ingredient/ingredient-provider.d.ts.map +1 -1
  108. package/ui/contexts/ingredient-container/ingredient-container-provider.d.ts +8 -0
  109. package/ui/contexts/ingredient-container/ingredient-container-provider.d.ts.map +1 -1
  110. package/ui/contexts/nozzle/nozzle-provider.d.ts +8 -0
  111. package/ui/contexts/nozzle/nozzle-provider.d.ts.map +1 -1
  112. package/ui/contexts/pump/pump-provider.d.ts +8 -0
  113. package/ui/contexts/pump/pump-provider.d.ts.map +1 -1
  114. package/ui/hooks/assembly/use-assembly.d.ts +4 -0
  115. package/ui/hooks/assembly/use-assembly.d.ts.map +1 -1
  116. package/ui/hooks/assembly/with-assembly.d.ts +4 -0
  117. package/ui/hooks/assembly/with-assembly.d.ts.map +1 -1
  118. package/ui/hooks/availability/use-availability.d.ts +4 -0
  119. package/ui/hooks/availability/use-availability.d.ts.map +1 -1
  120. package/ui/hooks/board/use-board.d.ts +4 -0
  121. package/ui/hooks/board/use-board.d.ts.map +1 -1
  122. package/ui/hooks/board/with-board.d.ts +4 -0
  123. package/ui/hooks/board/with-board.d.ts.map +1 -1
  124. package/ui/hooks/board-container/use-board-container.d.ts +4 -0
  125. package/ui/hooks/board-container/use-board-container.d.ts.map +1 -1
  126. package/ui/hooks/board-container/with-board-container.d.ts +4 -0
  127. package/ui/hooks/board-container/with-board-container.d.ts.map +1 -1
  128. package/ui/hooks/cui-kit/use-ambient-attract-timers.d.ts.map +1 -1
  129. package/ui/hooks/cui-kit/use-brands.d.ts.map +1 -1
  130. package/ui/hooks/cui-kit/use-cui-kit.d.ts +50 -5
  131. package/ui/hooks/cui-kit/use-cui-kit.d.ts.map +1 -1
  132. package/ui/hooks/cui-kit/use-default-cui-kit-lifecycle.d.ts.map +1 -1
  133. package/ui/hooks/cui-kit/use-dispense-timers.d.ts.map +1 -1
  134. package/ui/hooks/device-assembly/use-device-assembly.d.ts +4 -0
  135. package/ui/hooks/device-assembly/use-device-assembly.d.ts.map +1 -1
  136. package/ui/hooks/device-assembly/with-device-assembly.d.ts +4 -0
  137. package/ui/hooks/device-assembly/with-device-assembly.d.ts.map +1 -1
  138. package/ui/hooks/generic-pour/use-generic-pour.d.ts +4 -0
  139. package/ui/hooks/generic-pour/use-generic-pour.d.ts.map +1 -1
  140. package/ui/hooks/generic-pour/with-generic-pour.d.ts +4 -0
  141. package/ui/hooks/generic-pour/with-generic-pour.d.ts.map +1 -1
  142. package/ui/hooks/holder/use-holder.d.ts +4 -0
  143. package/ui/hooks/holder/use-holder.d.ts.map +1 -1
  144. package/ui/hooks/holder/with-holder.d.ts +4 -0
  145. package/ui/hooks/holder/with-holder.d.ts.map +1 -1
  146. package/ui/hooks/holder-container/use-holder-container.d.ts +4 -0
  147. package/ui/hooks/holder-container/use-holder-container.d.ts.map +1 -1
  148. package/ui/hooks/holder-container/with-holder-container.d.ts +4 -0
  149. package/ui/hooks/holder-container/with-holder-container.d.ts.map +1 -1
  150. package/ui/hooks/ingredient/use-ingredient-pour.d.ts +7 -1
  151. package/ui/hooks/ingredient/use-ingredient-pour.d.ts.map +1 -1
  152. package/ui/hooks/ingredient/use-ingredient.d.ts +4 -0
  153. package/ui/hooks/ingredient/use-ingredient.d.ts.map +1 -1
  154. package/ui/hooks/ingredient/with-ingredient.d.ts +4 -0
  155. package/ui/hooks/ingredient/with-ingredient.d.ts.map +1 -1
  156. package/ui/hooks/ingredient-container/use-ingredient-container.d.ts +4 -0
  157. package/ui/hooks/ingredient-container/use-ingredient-container.d.ts.map +1 -1
  158. package/ui/hooks/ingredient-container/with-ingredient-container.d.ts +4 -0
  159. package/ui/hooks/ingredient-container/with-ingredient-container.d.ts.map +1 -1
  160. package/ui/hooks/nozzle/use-nozzle.d.ts +4 -0
  161. package/ui/hooks/nozzle/use-nozzle.d.ts.map +1 -1
  162. package/ui/hooks/nozzle/with-nozzle.d.ts +4 -0
  163. package/ui/hooks/nozzle/with-nozzle.d.ts.map +1 -1
  164. package/ui/hooks/nozzle-pour/use-nozzle-pour.d.ts +7 -1
  165. package/ui/hooks/nozzle-pour/use-nozzle-pour.d.ts.map +1 -1
  166. package/ui/hooks/pour/use-pour.d.ts.map +1 -1
  167. package/ui/hooks/utils/pour-strategy/hold-to-pour-intent-strategy.d.ts +4 -0
  168. package/ui/hooks/utils/pour-strategy/hold-to-pour-intent-strategy.d.ts.map +1 -1
  169. package/ui/hooks/utils/pour-strategy/hold-to-pour-strategy.d.ts +4 -0
  170. package/ui/hooks/utils/pour-strategy/hold-to-pour-strategy.d.ts.map +1 -1
  171. package/ui/hooks/utils/pour-strategy/pour-strategy.d.ts +10 -0
  172. package/ui/hooks/utils/pour-strategy/pour-strategy.d.ts.map +1 -1
  173. package/ui/hooks/utils/pour-strategy/tap-or-hold-to-pour-intent-strategy.d.ts +4 -0
  174. package/ui/hooks/utils/pour-strategy/tap-or-hold-to-pour-intent-strategy.d.ts.map +1 -1
  175. package/ui/hooks/utils/pour-strategy/tap-to-pour-intent-strategy.d.ts +4 -0
  176. package/ui/hooks/utils/pour-strategy/tap-to-pour-intent-strategy.d.ts.map +1 -1
  177. package/ui/hooks/utils/pour-strategy/tap-to-pour-strategy.d.ts +4 -0
  178. package/ui/hooks/utils/pour-strategy/tap-to-pour-strategy.d.ts.map +1 -1
  179. package/ui/utils/pour-context.d.ts +1 -7
  180. package/ui/utils/pour-context.d.ts.map +1 -1
  181. package/ui.cjs +3 -2
  182. package/ui.cjs.map +1 -1
  183. package/ui.js +49 -48
  184. package/ui.js.map +1 -1
  185. package/dispense-registration-manager-Da9CW_cN.js.map +0 -1
  186. package/dispense-registration-manager-Dtb31fcI.cjs.map +0 -1
  187. package/extension-utils-Cfhe358W.cjs.map +0 -1
  188. package/extension-utils-D_dnBLH6.js.map +0 -1
  189. package/pump-provider-BQmCKz7S.js.map +0 -1
  190. package/pump-provider-uNNMh9uh.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { jsx } from "@emotion/react/jsx-runtime";
2
- import { useKosModel, getKosCompanionModel, kosAutoEffect, KosLog, usePressGesture, EventBus, TimerManager } from "@kosdev-code/kos-ui-sdk";
3
- import { A as Assembly$1, a as Availability$1, B as Board$1, b as BoardContainer$1, N as Nozzle$1, D as DeviceAssembly, H as Holder$1, f as HolderContainer$1, I as Ingredient$1, g as IngredientContainer$1, G as GenericPour, h as Pump$1 } from "./dispense-registration-manager-Da9CW_cN.js";
2
+ import { useKosModel, getKosCompanionModel, kosAutoEffect, KosLog, LogGroup, whenReady, usePressGesture, TimerManager, EventBus } from "@kosdev-code/kos-ui-sdk";
4
3
  import React, { createContext, useMemo, useContext, useState, useCallback, useEffect, useRef } from "react";
4
+ import { A as Assembly$1, a as Availability$1, B as Board$1, b as BoardContainer$1, N as Nozzle$1, e as CuiKitState, X as cuiKitId, D as DeviceAssembly, H as Holder$1, g as HolderContainer$1, I as Ingredient$1, h as IngredientContainer$1, P as PourContext, G as GenericPour, j as Pump$1 } from "./dispense-registration-manager-DtN0T_JG.js";
5
5
  const useAssembly = () => {
6
6
  const modelId = Assembly$1.type;
7
7
  const result = useKosModel({
@@ -145,6 +145,7 @@ const useBeverages = ({
145
145
  clearBeverage
146
146
  };
147
147
  };
148
+ const log$4 = KosLog.createLogger({ group: LogGroup.ui, name: "use-brands" });
148
149
  const useBrands = ({
149
150
  onBrandSelected,
150
151
  onBrandCleared,
@@ -161,9 +162,7 @@ const useBrands = ({
161
162
  async (brand, context, forceUpdate) => {
162
163
  setSelectedBrand(brand);
163
164
  if (forceUpdate) {
164
- KosLog.warn(
165
- `forceUpdate is not currently supported when setting brand`
166
- );
165
+ log$4.warn(`forceUpdate is not currently supported when setting brand`);
167
166
  }
168
167
  nozzle?.setSelectedBrand(brand, context);
169
168
  onBrandSelected?.(brand);
@@ -192,30 +191,39 @@ const useBrands = ({
192
191
  clearBrand
193
192
  };
194
193
  };
195
- class PourContext {
196
- _data = /* @__PURE__ */ new Map();
197
- get(key) {
198
- return this._data.get(key);
199
- }
200
- set(key, value) {
201
- this._data.set(key, value);
202
- }
203
- remove(key) {
204
- this._data.delete(key);
205
- }
206
- has(key) {
207
- return this._data.has(key);
208
- }
209
- }
210
194
  const logger$7 = KosLog.createLogger({
211
- name: "HoldToPourStrategy",
212
- group: "kos-hooks"
195
+ group: LogGroup.ui,
196
+ name: "HoldToPourIntentStrategy"
197
+ });
198
+ const HoldToPourIntentStrategy = {
199
+ name: "HoldToPourIntentStrategy",
200
+ requiresHold: true,
201
+ async initiate(model, intent) {
202
+ if (!model?.canPour) {
203
+ logger$7.debug(`${model?.id} cannot pour. Returning early.`);
204
+ return;
205
+ }
206
+ if (intent) {
207
+ logger$7.debug(`performing intent: ${intent}`);
208
+ await model?.performIntent(intent);
209
+ } else {
210
+ logger$7.debug("no intent provided. Returning early.");
211
+ }
212
+ },
213
+ async initiateEnded(nozzle) {
214
+ await nozzle?.cancelPour();
215
+ }
216
+ };
217
+ const logger$6 = KosLog.createLogger({
218
+ group: LogGroup.ui,
219
+ name: "HoldToPourStrategy"
213
220
  });
214
221
  const HoldToPourStrategy = {
215
222
  name: "HoldToPourStrategy",
223
+ requiresHold: true,
216
224
  async initiate(nozzle) {
217
225
  if (!nozzle?.canPour) {
218
- logger$7.debug(`Nozzle ${nozzle?.id} cannot pour. Returning early.`);
226
+ logger$6.debug(`Nozzle ${nozzle?.id} cannot pour. Returning early.`);
219
227
  return;
220
228
  }
221
229
  await nozzle?.pour();
@@ -224,297 +232,191 @@ const HoldToPourStrategy = {
224
232
  await nozzle?.cancelPour();
225
233
  }
226
234
  };
227
- const logger$6 = KosLog.createLogger({
228
- name: "useNozzlePour",
229
- group: "kos-hooks"
235
+ const logger$5 = KosLog.createLogger({
236
+ group: LogGroup.ui,
237
+ name: "TapOrHoldIntentStrategy"
230
238
  });
231
- const useNozzlePour = ({
232
- onPour,
233
- onPourCancel,
234
- onBeforePour,
235
- onBeforePourRejected,
236
- pourContext,
237
- strategy = HoldToPourStrategy
238
- }) => {
239
- const { model: nozzle } = useNozzleContext();
240
- const [context, _setContext] = useState(
241
- pourContext || new PourContext()
242
- );
243
- const handlePour = useCallback(async () => {
244
- const canPour = onBeforePour ? await onBeforePour?.(context) : true;
245
- if (canPour) {
246
- logger$6.debug(
247
- `[${strategy?.name}] - Pour initiated for nozzle ${nozzle?.id}.`
248
- );
249
- strategy?.initiate(nozzle);
250
- onPour?.();
239
+ class TapOrHoldIntentStrategy {
240
+ intent;
241
+ name = "TapOrHoldIntentStrategy";
242
+ isHold = false;
243
+ disposer = null;
244
+ constructor(intent) {
245
+ this.intent = intent;
246
+ }
247
+ async initiate(model, intent = this.intent) {
248
+ this.isHold = false;
249
+ this.disposer = setTimeout(() => {
250
+ this.isHold = true;
251
+ }, 250);
252
+ if (model?.isPouring && !this.isHold) {
253
+ logger$5.debug(`additional tap detected. cancelling pour`);
254
+ await model.cancelPour();
255
+ return;
256
+ }
257
+ if (!model?.canPour) {
258
+ logger$5.debug(`${model?.id} cannot pour. Returning early.`);
259
+ return;
260
+ }
261
+ if (intent) {
262
+ logger$5.debug(`performing intent: ${intent}`);
263
+ await model?.performIntent(intent);
251
264
  } else {
252
- logger$6.debug(
253
- `[${strategy?.name}] - Did not pass onBeforePour gate for nozzle ${nozzle?.id}. Cancelling pour.`
254
- );
255
- onBeforePourRejected?.();
265
+ logger$5.debug("no intent provided. Returning early.");
256
266
  }
257
- }, [
258
- onPour,
259
- nozzle,
260
- strategy,
261
- onBeforePour,
262
- onPourCancel,
263
- context,
264
- onBeforePourRejected
265
- ]);
266
- const handleCancelPour = useCallback(() => {
267
- logger$6.debug(
268
- `[${strategy?.name}] - Pour initiate ended called for nozzle ${nozzle?.id}.`
269
- );
270
- strategy?.initiateEnded?.(nozzle);
271
- onPourCancel?.();
272
- }, [onPourCancel, nozzle, strategy]);
273
- const forceCancelPour = useCallback(() => {
274
- logger$6.debug(`Force cancelling pour for nozzle ${nozzle?.id}.`);
275
- nozzle?.cancelPour();
276
- onPourCancel?.();
277
- }, [onPourCancel, nozzle]);
278
- const handleUpdateContext = useCallback(
279
- (key, value) => {
280
- context.set(key, value);
281
- },
282
- [context]
283
- );
284
- const handleRemoveFromContext = useCallback(
285
- (key) => {
286
- context.remove(key);
287
- },
288
- [context]
289
- );
290
- const handlers = usePressGesture({
291
- onPressed: handlePour,
292
- onRelease: handleCancelPour
293
- });
294
- return {
295
- handlers: handlers.dom,
296
- cancel: forceCancelPour,
297
- updatePourContext: handleUpdateContext,
298
- removeFromPourContext: handleRemoveFromContext,
299
- status: nozzle
300
- };
267
+ }
268
+ async initiateEnded(nozzle) {
269
+ if (this.disposer) clearTimeout(this.disposer);
270
+ this.disposer = null;
271
+ if (!this.isHold) {
272
+ logger$5.debug("Tap detected. don't cancel and return.");
273
+ return true;
274
+ }
275
+ await nozzle?.cancelPour();
276
+ return false;
277
+ }
278
+ }
279
+ const logger$4 = KosLog.createLogger({
280
+ group: LogGroup.ui,
281
+ name: "TapToPourIntentStrategy"
282
+ });
283
+ const TapToPourIntentStrategy = {
284
+ name: "TapToPourIntentStrategy",
285
+ async initiate(model, intent) {
286
+ if (model?.isPouring) {
287
+ logger$4.debug(`Nozzle ${model?.id} is already pouring. cancelling pour`);
288
+ await model.cancelPour();
289
+ return;
290
+ }
291
+ if (!model?.canPour) {
292
+ logger$4.debug(`Nozzle ${model?.id} cannot pour. Returning early.`);
293
+ return;
294
+ }
295
+ if (intent) {
296
+ logger$4.debug(`performing intent: ${intent}`);
297
+ await model?.performIntent(intent);
298
+ } else {
299
+ logger$4.debug("no intent provided. Returning early.");
300
+ }
301
+ },
302
+ async initiateEnded(_nozzle) {
303
+ return true;
304
+ }
301
305
  };
302
- const useFlavors = ({
303
- onFlavorSelected,
304
- onFlavorCleared,
305
- companionType
306
- }) => {
307
- const { model: nozzle } = useNozzleContext();
308
- const flavors = useMemo(
309
- () => nozzle?.getGroupAvailabilityItems("flavors").filter((f) => f.visible) ?? [],
310
- [nozzle]
311
- );
312
- const companions = useMemo(() => {
313
- if (!companionType) return [];
314
- return flavors.map(
315
- (flavor) => getKosCompanionModel(flavor, companionType)
316
- );
317
- }, [flavors, companionType]);
318
- const [selectedFlavors, setSelectedFlavors] = useState([]);
319
- const selectFlavor = useCallback(
320
- async (flavor, context, forceUpdate) => {
321
- setSelectedFlavors(
322
- (previous) => previous?.includes(flavor) ? [...previous.filter((p) => p !== flavor)] : [...previous ?? [], flavor]
323
- );
324
- if (nozzle?.selectedPourable) {
325
- const { beverage } = nozzle.selectedPourable;
326
- await nozzle.setSelectedPourable(
327
- {
328
- beverage,
329
- additional: selectedFlavors ?? [],
330
- context
331
- },
332
- forceUpdate
333
- );
334
- }
335
- onFlavorSelected?.(flavor, selectedFlavors ?? []);
336
- },
337
- [nozzle, onFlavorSelected, selectedFlavors]
338
- );
339
- const clear = useCallback(async () => {
340
- setSelectedFlavors([]);
341
- if (nozzle?.selectedPourable) {
342
- const { beverage } = nozzle.selectedPourable;
343
- nozzle.setSelectedPourable({ beverage });
344
- onFlavorCleared?.();
306
+ const logger$3 = KosLog.createLogger({
307
+ group: LogGroup.ui,
308
+ name: "HoldToPourStrategy"
309
+ });
310
+ const TapToPourStrategy = {
311
+ name: "TapToPourStrategy",
312
+ async initiate(nozzle) {
313
+ if (nozzle?.isPouring) {
314
+ logger$3.debug(`Nozzle ${nozzle?.id} is already pouring. cancelling pour`);
315
+ await nozzle.cancelPour();
316
+ return;
345
317
  }
346
- }, [nozzle, onFlavorCleared]);
347
- return {
348
- flavors,
349
- flavorCompanions: companions,
350
- selectFlavor,
351
- selectedFlavors,
352
- clearFlavors: clear
353
- };
318
+ if (!nozzle?.canPour) {
319
+ logger$3.debug(`Nozzle ${nozzle?.id} cannot pour. Returning early.`);
320
+ return;
321
+ }
322
+ await nozzle?.pour();
323
+ },
324
+ async initiateEnded(_nozzle) {
325
+ return true;
326
+ }
354
327
  };
355
328
  const DISPENSE_GROUP_BRAND = "brands";
356
329
  const DISPENSE_GROUP_BEVERAGE = "beverages";
357
330
  const DISPENSE_GROUP_FLAVOR = "flavors";
358
- const log$2 = KosLog.createLogger({ name: "use-cui-kit" });
331
+ const log$3 = KosLog.createLogger({ group: LogGroup.ui, name: "use-cui-kit" });
359
332
  const useCuiKit = ({
360
- initialGroup = DISPENSE_GROUP_BRAND,
333
+ initialGroup,
334
+ steps,
361
335
  options = {}
362
336
  }) => {
363
- const [currentGroup, setCurrentGroup] = useState(initialGroup);
364
337
  const { model: nozzle } = useNozzleContext();
365
338
  const timersRef = useRef([]);
366
- const updatePourContext = useRef();
367
- const removeFromPourContext = useRef();
368
- const onBrandSelected = useCallback(
369
- (model) => {
370
- setCurrentGroup(DISPENSE_GROUP_BEVERAGE);
371
- const topic = `/kos/dispense/${nozzle?.path}/brand/selected/`;
372
- EventBus.publish(topic, model);
373
- },
374
- [nozzle?.path]
375
- );
376
- const onBrandCleared = useCallback(() => {
377
- const topic = `/kos/dispense/${nozzle?.path}/brand/cleared/`;
378
- EventBus.publish(topic, {});
379
- }, [nozzle?.path]);
380
- const onBeverageListUpdated = useCallback(
381
- (beverages2) => {
382
- const topic = `/kos/dispense/${nozzle?.path}/beverage/list/updated/`;
383
- EventBus.publish(topic, beverages2);
384
- },
385
- [nozzle?.path]
386
- );
387
- const onBeverageSelected = useCallback(
388
- (model) => {
389
- setCurrentGroup(DISPENSE_GROUP_FLAVOR);
390
- updatePourContext.current?.("selectedBeverage", model);
391
- const topic = `/kos/dispense/${nozzle?.path}/beverage/selected/`;
392
- EventBus.publish(topic, model);
393
- },
394
- [nozzle?.path]
395
- );
396
- const onBeverageCleared = useCallback(() => {
397
- const topic = `/kos/dispense/${nozzle?.path}/beverage/cleared/`;
398
- removeFromPourContext.current?.("selectedBeverage");
399
- EventBus.publish(topic, {});
400
- }, [nozzle?.path]);
401
- const onFlavorSelected = useCallback(
402
- (model) => {
403
- const topic = `/kos/dispense/${nozzle?.path}/flavor/selected/`;
404
- EventBus.publish(topic, model);
405
- },
406
- [nozzle?.path]
407
- );
408
- const onFlavorCleared = useCallback(() => {
409
- const topic = `/kos/dispense/${nozzle?.path}/flavor/cleared/`;
410
- EventBus.publish(topic, {});
411
- }, [nozzle?.path]);
412
- const onPour = useCallback(() => {
413
- const topic = `/kos/dispense/${nozzle?.path}/pour/`;
414
- EventBus.publish(topic, {});
415
- }, [nozzle?.path]);
416
- const handleBeforePour = useCallback(
417
- async (context) => {
418
- const topic = `/kos/dispense/${nozzle?.path}/pre/pour/`;
419
- EventBus.publish(topic, {});
420
- return await onBeforePour?.(context) || true;
339
+ const kit = useMemo(() => {
340
+ if (!nozzle) return void 0;
341
+ try {
342
+ return CuiKitState.instance(cuiKitId(nozzle.path)).options({
343
+ nozzlePath: nozzle.path,
344
+ initialGroup: steps ? initialGroup : initialGroup ?? DISPENSE_GROUP_BRAND,
345
+ steps,
346
+ companionTypes: options.companionTypes,
347
+ pour: { strategy: options.pour?.strategy ?? HoldToPourStrategy },
348
+ onPourComplete: options.onPourComplete
349
+ }).build();
350
+ } catch (error) {
351
+ throw new Error(
352
+ `The CUI Kit models are not registered: call KosModelRegistry.cuiKit.models() in the app's registration chain (${error.message})`
353
+ );
354
+ }
355
+ }, [nozzle]);
356
+ const [ready, setReady] = useState(false);
357
+ const [, setVersion] = useState(0);
358
+ useEffect(() => {
359
+ if (!kit) return void 0;
360
+ let dispose;
361
+ let cancelled = false;
362
+ let attached = false;
363
+ whenReady(kit).then(() => {
364
+ if (cancelled) return;
365
+ attached = true;
366
+ if (kit.attach()) {
367
+ kit.reset();
368
+ }
369
+ setReady(true);
370
+ dispose = kosAutoEffect(() => {
371
+ readKitState(kit);
372
+ setVersion((version) => version + 1);
373
+ });
374
+ });
375
+ return () => {
376
+ cancelled = true;
377
+ dispose?.();
378
+ if (attached) kit.detach();
379
+ };
380
+ }, [kit]);
381
+ const updateOnBeforePour = useCallback(
382
+ (callback) => {
383
+ kit?.setBeforePour(callback);
421
384
  },
422
- [nozzle?.path]
385
+ [kit]
423
386
  );
424
- const handleBeforePourRejected = useCallback(async () => {
425
- const topic = `/kos/dispense/${nozzle?.path}/pre/pour/rejected/`;
426
- EventBus.publish(topic, {});
427
- }, [nozzle?.path]);
428
- const onPourCancel = useCallback(() => {
429
- const topic = `/kos/dispense/${nozzle?.path}/pour/cancel/`;
430
- EventBus.publish(topic, {});
431
- }, [nozzle?.path]);
432
- const { brands, selectBrand, selectedBrand, clearBrand, brandCompanions } = useBrands({
433
- companionType: options.companionTypes?.brand,
434
- onBrandSelected,
435
- onBrandCleared
387
+ const gesture = usePressGesture({
388
+ onPressed: () => void kit?.pressPour(),
389
+ onRelease: () => kit?.releasePour()
436
390
  });
437
- const {
438
- beverages,
439
- selectBeverage,
440
- selectedBeverage,
441
- clearBeverage,
442
- beverageCompanions
443
- } = useBeverages({
444
- companionType: options.companionTypes?.beverage,
445
- onBeverageSelected,
446
- onClearBeverage: onBeverageCleared,
447
- onBeverageListUpdated
448
- });
449
- const {
450
- clearFlavors,
451
- flavors,
452
- selectFlavor,
453
- selectedFlavors,
454
- flavorCompanions
455
- } = useFlavors({
456
- companionType: options.companionTypes?.flavor,
457
- onFlavorSelected,
458
- onFlavorCleared
459
- });
460
- const [onBeforePour, setOnBeforePour] = useState();
461
- const updateOnBeforePour = useCallback((callback) => {
462
- setOnBeforePour(() => callback);
463
- }, []);
464
- const pour = useNozzlePour({
465
- onPour,
466
- onPourCancel,
467
- onBeforePour: handleBeforePour,
468
- onBeforePourRejected: handleBeforePourRejected
469
- });
470
- updatePourContext.current = pour.updatePourContext;
471
- removeFromPourContext.current = pour.removeFromPourContext;
472
- const back = useCallback(() => {
473
- log$2.debug(`Navigating back from group: ${currentGroup}`);
474
- switch (currentGroup) {
475
- case DISPENSE_GROUP_BRAND:
476
- clearBeverage();
477
- clearBrand();
478
- break;
479
- case DISPENSE_GROUP_BEVERAGE:
480
- case DISPENSE_GROUP_FLAVOR:
481
- setCurrentGroup(initialGroup);
482
- clearBeverage();
483
- clearBrand();
484
- break;
485
- }
486
- }, [clearBeverage, clearBrand, currentGroup, initialGroup]);
487
- const home = useCallback(() => {
488
- const topic = `/kos/dispense/${nozzle?.path}/home/`;
489
- EventBus.publish(topic, {});
490
- setCurrentGroup(initialGroup);
491
- if (initialGroup === DISPENSE_GROUP_BRAND) {
492
- clearBeverage();
493
- clearBrand();
494
- }
495
- if (initialGroup === DISPENSE_GROUP_BEVERAGE) {
496
- clearBeverage();
497
- }
498
- }, [clearBeverage, clearBrand, initialGroup]);
391
+ const pour = {
392
+ handlers: gesture.dom,
393
+ cancel: () => void kit?.cancelPour(),
394
+ start: async (pourOptions) => await kit?.startPour(pourOptions) ?? false,
395
+ press: async (pourOptions) => await kit?.pressPour(pourOptions) ?? false,
396
+ release: (pourOptions) => kit?.releasePour(pourOptions),
397
+ updatePourContext: (key, value) => kit?.pourContext.set(key, value),
398
+ removeFromPourContext: (key) => kit?.pourContext.remove(key),
399
+ status: nozzle
400
+ };
499
401
  const pauseTimers = useCallback(() => {
500
402
  if (timersRef.current.length === 0) {
501
- log$2.debug("No timers to pause.");
403
+ log$3.debug("No timers to pause.");
502
404
  return;
503
405
  }
504
- log$2.debug(`Pausing ${timersRef.current.length} timers.`);
406
+ log$3.debug(`Pausing ${timersRef.current.length} timers.`);
505
407
  timersRef.current.forEach((timer) => {
506
- log$2.debug(`Pausing timer with id ${timer.id}.`);
408
+ log$3.debug(`Pausing timer with id ${timer.id}.`);
507
409
  timer.pause();
508
410
  });
509
411
  }, []);
510
412
  const restartTimers = useCallback(() => {
511
413
  if (timersRef.current.length === 0) {
512
- log$2.debug("No timers to restart.");
414
+ log$3.debug("No timers to restart.");
513
415
  return;
514
416
  }
515
- log$2.debug(`Restarting ${timersRef.current.length} timers.`);
417
+ log$3.debug(`Restarting ${timersRef.current.length} timers.`);
516
418
  timersRef.current.forEach((timer) => {
517
- log$2.debug(`Restarting timer with id ${timer.id}.`);
419
+ log$3.debug(`Restarting timer with id ${timer.id}.`);
518
420
  timer.restart();
519
421
  });
520
422
  }, []);
@@ -523,11 +425,12 @@ const useCuiKit = ({
523
425
  return;
524
426
  }
525
427
  if (timersRef.current.some((t) => t.id === timer.id)) {
526
- log$2.debug(`Timer with id ${timer.id} already exists.`);
428
+ log$3.debug(`Timer with id ${timer.id} already exists.`);
527
429
  return;
528
430
  }
529
431
  timersRef.current.push(timer);
530
432
  }, []);
433
+ const active = ready ? kit : void 0;
531
434
  return {
532
435
  timers: {
533
436
  add: addTimer,
@@ -535,43 +438,70 @@ const useCuiKit = ({
535
438
  restart: restartTimers
536
439
  },
537
440
  nav: {
538
- currentGroup,
539
- back,
540
- home
441
+ currentGroup: active?.currentGroup ?? (steps ? steps.brands ? DISPENSE_GROUP_BRAND : DISPENSE_GROUP_BEVERAGE : initialGroup ?? DISPENSE_GROUP_BRAND),
442
+ back: () => active?.back(),
443
+ home: () => active?.home(),
444
+ steps: active?.enabledSteps,
445
+ canBack: active?.canBack ?? false,
446
+ toPour: (pourOptions) => active?.toPour(pourOptions)
541
447
  },
542
448
  pour,
543
449
  updateOnBeforePour,
544
450
  selections: {
545
- [DISPENSE_GROUP_BRAND]: selectedBrand,
546
- [DISPENSE_GROUP_BEVERAGE]: selectedBeverage,
547
- [DISPENSE_GROUP_FLAVOR]: selectedFlavors
451
+ [DISPENSE_GROUP_BRAND]: active?.selectedBrand ?? null,
452
+ [DISPENSE_GROUP_BEVERAGE]: active?.selectedBeverage ?? null,
453
+ [DISPENSE_GROUP_FLAVOR]: active?.selectedFlavors ?? []
548
454
  },
549
455
  [DISPENSE_GROUP_BRAND]: {
550
- models: brands,
551
- companions: brandCompanions,
552
- clear: clearBrand,
456
+ models: active?.brands ?? [],
457
+ companions: active?.brandCompanions ?? [],
458
+ clear: () => active?.clearBrand(),
553
459
  handlers: {
554
- onSelected: selectBrand
460
+ onSelected: async (model, context, forceUpdate) => {
461
+ if (forceUpdate) {
462
+ log$3.warn(
463
+ `forceUpdate is not currently supported when setting brand`
464
+ );
465
+ }
466
+ active?.selectBrand(model, context);
467
+ }
555
468
  }
556
469
  },
557
470
  [DISPENSE_GROUP_BEVERAGE]: {
558
- models: beverages,
559
- companions: beverageCompanions,
560
- clear: clearBeverage,
471
+ models: active?.beverages ?? [],
472
+ companions: active?.beverageCompanions ?? [],
473
+ clear: () => void active?.clearBeverage(),
561
474
  handlers: {
562
- onSelected: selectBeverage
475
+ onSelected: async (model, context, forceUpdate) => active?.selectBeverage(model, context, forceUpdate)
563
476
  }
564
477
  },
565
478
  [DISPENSE_GROUP_FLAVOR]: {
566
- models: flavors,
567
- companions: flavorCompanions,
568
- clear: clearFlavors,
479
+ models: active?.flavors ?? [],
480
+ companions: active?.flavorCompanions ?? [],
481
+ clear: () => void active?.clearFlavors(),
569
482
  handlers: {
570
- onSelected: selectFlavor
483
+ onSelected: async (model, context, forceUpdate) => active?.selectFlavor(model, context, forceUpdate)
571
484
  }
572
485
  }
573
486
  };
574
487
  };
488
+ const readKitState = (kit) => [
489
+ kit.currentGroup,
490
+ kit.canBack,
491
+ kit.selectedBrand,
492
+ kit.selectedBeverage,
493
+ ...kit.selectedFlavors,
494
+ ...kit.brands,
495
+ ...kit.beverages,
496
+ ...kit.flavors,
497
+ ...kit.brandCompanions,
498
+ ...kit.beverageCompanions,
499
+ ...kit.flavorCompanions
500
+ ];
501
+ const log$2 = KosLog.createLogger({
502
+ group: LogGroup.ui,
503
+ name: "use-ambient-attract-timers"
504
+ });
575
505
  const useAmbientAttractTimers = (props) => {
576
506
  const { model: nozzle } = useNozzleContext();
577
507
  const [attractTimer, setAttractTimer] = useState(null);
@@ -585,13 +515,13 @@ const useAmbientAttractTimers = (props) => {
585
515
  } = props;
586
516
  const handleAmbientTimer = useCallback(() => {
587
517
  if (onAmbientTimer) {
588
- KosLog.info("Ambient timer expired. Calling callback");
518
+ log$2.info("Ambient timer expired. Calling callback");
589
519
  onAmbientTimer?.();
590
520
  }
591
521
  }, [onAmbientTimer]);
592
522
  const handleAttractTimer = useCallback(() => {
593
523
  if (onAttractTimer) {
594
- KosLog.info("Attract timer expired. Calling callback");
524
+ log$2.info("Attract timer expired. Calling callback");
595
525
  onAttractTimer?.();
596
526
  }
597
527
  }, [onAttractTimer]);
@@ -615,7 +545,7 @@ const useAmbientAttractTimers = (props) => {
615
545
  }, [attractTimer, onResumeAttractTimer]);
616
546
  useEffect(() => {
617
547
  if (nozzle && defaultAttractTime) {
618
- KosLog.info("Nozzle is available. Creating timers");
548
+ log$2.info("Nozzle is available. Creating timers");
619
549
  const timer = TimerManager.createTimer(
620
550
  "attract-timer-" + nozzle.path,
621
551
  defaultAttractTime
@@ -644,7 +574,7 @@ const useAmbientAttractTimers = (props) => {
644
574
  };
645
575
  }
646
576
  return () => {
647
- KosLog.info("Nozzle is not available. No timers to clear");
577
+ log$2.info("Nozzle is not available. No timers to clear");
648
578
  };
649
579
  }, [
650
580
  defaultAmbientTime,
@@ -771,7 +701,10 @@ const useDispenseLifecycle = ({
771
701
  onReturnToHome
772
702
  ]);
773
703
  };
774
- const log$1 = KosLog.createLogger({ name: "useCuiKitTimers" });
704
+ const log$1 = KosLog.createLogger({
705
+ group: LogGroup.ui,
706
+ name: "useCuiKitTimers"
707
+ });
775
708
  const useCuiKitTimers = (props) => {
776
709
  const { model: nozzle } = useNozzleContext();
777
710
  const [idleTimer, setIdleTimer] = useState(null);
@@ -785,7 +718,7 @@ const useCuiKitTimers = (props) => {
785
718
  const hasAreYouThereFiredRef = useRef(false);
786
719
  const handleAreYouThereTimer = useCallback(() => {
787
720
  if (!hasAreYouThereFiredRef.current && onAreYouThereTimer) {
788
- KosLog.info("Are you there timer expired. Calling callback");
721
+ log$1.info("Are you there timer expired. Calling callback");
789
722
  hasAreYouThereFiredRef.current = true;
790
723
  onAreYouThereTimer?.();
791
724
  }
@@ -865,7 +798,10 @@ const useCuiKitTimers = (props) => {
865
798
  pause: handlePauseIdleTimer
866
799
  };
867
800
  };
868
- const log = KosLog.createLogger({ name: "useDefaultCuiKitLifecycle" });
801
+ const log = KosLog.createLogger({
802
+ group: LogGroup.ui,
803
+ name: "useDefaultCuiKitLifecycle"
804
+ });
869
805
  const useDefaultCuiKitLifecycle = ({
870
806
  kit,
871
807
  inactivity,
@@ -1121,6 +1057,59 @@ const useDefaultCuiKitLifecycle = ({
1121
1057
  restartScreenTimer: ambientRestart
1122
1058
  };
1123
1059
  };
1060
+ const useFlavors = ({
1061
+ onFlavorSelected,
1062
+ onFlavorCleared,
1063
+ companionType
1064
+ }) => {
1065
+ const { model: nozzle } = useNozzleContext();
1066
+ const flavors = useMemo(
1067
+ () => nozzle?.getGroupAvailabilityItems("flavors").filter((f) => f.visible) ?? [],
1068
+ [nozzle]
1069
+ );
1070
+ const companions = useMemo(() => {
1071
+ if (!companionType) return [];
1072
+ return flavors.map(
1073
+ (flavor) => getKosCompanionModel(flavor, companionType)
1074
+ );
1075
+ }, [flavors, companionType]);
1076
+ const [selectedFlavors, setSelectedFlavors] = useState([]);
1077
+ const selectFlavor = useCallback(
1078
+ async (flavor, context, forceUpdate) => {
1079
+ setSelectedFlavors(
1080
+ (previous) => previous?.includes(flavor) ? [...previous.filter((p) => p !== flavor)] : [...previous ?? [], flavor]
1081
+ );
1082
+ if (nozzle?.selectedPourable) {
1083
+ const { beverage } = nozzle.selectedPourable;
1084
+ await nozzle.setSelectedPourable(
1085
+ {
1086
+ beverage,
1087
+ additional: selectedFlavors ?? [],
1088
+ context
1089
+ },
1090
+ forceUpdate
1091
+ );
1092
+ }
1093
+ onFlavorSelected?.(flavor, selectedFlavors ?? []);
1094
+ },
1095
+ [nozzle, onFlavorSelected, selectedFlavors]
1096
+ );
1097
+ const clear = useCallback(async () => {
1098
+ setSelectedFlavors([]);
1099
+ if (nozzle?.selectedPourable) {
1100
+ const { beverage } = nozzle.selectedPourable;
1101
+ nozzle.setSelectedPourable({ beverage });
1102
+ onFlavorCleared?.();
1103
+ }
1104
+ }, [nozzle, onFlavorCleared]);
1105
+ return {
1106
+ flavors,
1107
+ flavorCompanions: companions,
1108
+ selectFlavor,
1109
+ selectedFlavors,
1110
+ clearFlavors: clear
1111
+ };
1112
+ };
1124
1113
  const useDeviceAssembly = () => {
1125
1114
  const modelId = DeviceAssembly.type;
1126
1115
  const result = useKosModel({
@@ -1175,31 +1164,9 @@ const useIngredient = () => {
1175
1164
  });
1176
1165
  return result;
1177
1166
  };
1178
- const logger$5 = KosLog.createLogger({
1179
- name: "HoldToPourIntentStrategy",
1180
- group: "kos-hooks"
1181
- });
1182
- const HoldToPourIntentStrategy = {
1183
- name: "HoldToPourIntentStrategy",
1184
- async initiate(model, intent) {
1185
- if (!model?.canPour) {
1186
- logger$5.debug(`${model?.id} cannot pour. Returning early.`);
1187
- return;
1188
- }
1189
- if (intent) {
1190
- logger$5.debug(`performing intent: ${intent}`);
1191
- await model?.performIntent(intent);
1192
- } else {
1193
- logger$5.debug("no intent provided. Returning early.");
1194
- }
1195
- },
1196
- async initiateEnded(nozzle) {
1197
- await nozzle?.cancelPour();
1198
- }
1199
- };
1200
- const logger$4 = KosLog.createLogger({
1201
- name: "useNozzlePour",
1202
- group: "kos-hooks"
1167
+ const logger$2 = KosLog.createLogger({
1168
+ group: LogGroup.ui,
1169
+ name: "useNozzlePour"
1203
1170
  });
1204
1171
  const useIngredientPour = ({
1205
1172
  onPour,
@@ -1208,21 +1175,21 @@ const useIngredientPour = ({
1208
1175
  strategy = HoldToPourIntentStrategy
1209
1176
  }) => {
1210
1177
  const handlePour = useCallback(() => {
1211
- logger$4.debug(
1178
+ logger$2.debug(
1212
1179
  `[${strategy?.name}] - Pour initiated for model ${intentContainer?.id}.`
1213
1180
  );
1214
1181
  strategy?.initiate(intentContainer);
1215
1182
  onPour?.();
1216
1183
  }, [onPour, intentContainer, strategy]);
1217
1184
  const handleCancelPour = useCallback(() => {
1218
- logger$4.debug(
1185
+ logger$2.debug(
1219
1186
  `[${strategy?.name}] - Pour initiate ended called for nozzle ${intentContainer?.id}.`
1220
1187
  );
1221
1188
  strategy?.initiateEnded?.(intentContainer);
1222
1189
  onPourCancel?.();
1223
1190
  }, [onPourCancel, intentContainer, strategy]);
1224
1191
  const forceCancelPour = useCallback(() => {
1225
- logger$4.debug(`Force cancelling pour for nozzle ${intentContainer?.id}.`);
1192
+ logger$2.debug(`Force cancelling pour for nozzle ${intentContainer?.id}.`);
1226
1193
  intentContainer?.cancelPour();
1227
1194
  onPourCancel?.();
1228
1195
  }, [onPourCancel, intentContainer]);
@@ -1263,10 +1230,82 @@ function withNozzle(path, WrappedComponent) {
1263
1230
  return /* @__PURE__ */ jsx(KosModelLoader, { ...status, children: /* @__PURE__ */ jsx(WrappedComponent, { ...props, nozzle: model }) });
1264
1231
  };
1265
1232
  }
1266
- const logger$3 = KosLog.createLogger({
1267
- name: "usePour",
1268
- group: "kos-hooks"
1233
+ const logger$1 = KosLog.createLogger({
1234
+ group: LogGroup.ui,
1235
+ name: "useNozzlePour"
1269
1236
  });
1237
+ const useNozzlePour = ({
1238
+ onPour,
1239
+ onPourCancel,
1240
+ onBeforePour,
1241
+ onBeforePourRejected,
1242
+ pourContext,
1243
+ strategy = HoldToPourStrategy
1244
+ }) => {
1245
+ const { model: nozzle } = useNozzleContext();
1246
+ const [context, _setContext] = useState(
1247
+ pourContext || new PourContext()
1248
+ );
1249
+ const handlePour = useCallback(async () => {
1250
+ const canPour = onBeforePour ? await onBeforePour?.(context) : true;
1251
+ if (canPour) {
1252
+ logger$1.debug(
1253
+ `[${strategy?.name}] - Pour initiated for nozzle ${nozzle?.id}.`
1254
+ );
1255
+ strategy?.initiate(nozzle);
1256
+ onPour?.();
1257
+ } else {
1258
+ logger$1.debug(
1259
+ `[${strategy?.name}] - Did not pass onBeforePour gate for nozzle ${nozzle?.id}. Cancelling pour.`
1260
+ );
1261
+ onBeforePourRejected?.();
1262
+ }
1263
+ }, [
1264
+ onPour,
1265
+ nozzle,
1266
+ strategy,
1267
+ onBeforePour,
1268
+ onPourCancel,
1269
+ context,
1270
+ onBeforePourRejected
1271
+ ]);
1272
+ const handleCancelPour = useCallback(() => {
1273
+ logger$1.debug(
1274
+ `[${strategy?.name}] - Pour initiate ended called for nozzle ${nozzle?.id}.`
1275
+ );
1276
+ strategy?.initiateEnded?.(nozzle);
1277
+ onPourCancel?.();
1278
+ }, [onPourCancel, nozzle, strategy]);
1279
+ const forceCancelPour = useCallback(() => {
1280
+ logger$1.debug(`Force cancelling pour for nozzle ${nozzle?.id}.`);
1281
+ nozzle?.cancelPour();
1282
+ onPourCancel?.();
1283
+ }, [onPourCancel, nozzle]);
1284
+ const handleUpdateContext = useCallback(
1285
+ (key, value) => {
1286
+ context.set(key, value);
1287
+ },
1288
+ [context]
1289
+ );
1290
+ const handleRemoveFromContext = useCallback(
1291
+ (key) => {
1292
+ context.remove(key);
1293
+ },
1294
+ [context]
1295
+ );
1296
+ const handlers = usePressGesture({
1297
+ onPressed: handlePour,
1298
+ onRelease: handleCancelPour
1299
+ });
1300
+ return {
1301
+ handlers: handlers.dom,
1302
+ cancel: forceCancelPour,
1303
+ updatePourContext: handleUpdateContext,
1304
+ removeFromPourContext: handleRemoveFromContext,
1305
+ status: nozzle
1306
+ };
1307
+ };
1308
+ const logger = KosLog.createLogger({ group: LogGroup.ui, name: "usePour" });
1270
1309
  const usePourTarget = ({
1271
1310
  onBeforePour,
1272
1311
  onPour,
@@ -1280,12 +1319,12 @@ const usePourTarget = ({
1280
1319
  pourContext || new PourContext()
1281
1320
  );
1282
1321
  const handlePour = useCallback(async () => {
1283
- logger$3.debug(
1322
+ logger.debug(
1284
1323
  `[${strategy?.name}] - calling before pour for pour target ${pourTarget?.id}.`
1285
1324
  );
1286
1325
  const canPour = onBeforePour ? await onBeforePour?.(context) : true;
1287
1326
  if (canPour) {
1288
- logger$3.debug(
1327
+ logger.debug(
1289
1328
  `[${strategy?.name}] - Pour initiated for pour target ${pourTarget?.id}.`
1290
1329
  );
1291
1330
  await strategy?.initiate(pourTarget);
@@ -1294,14 +1333,14 @@ const usePourTarget = ({
1294
1333
  onPourAbort?.();
1295
1334
  }
1296
1335
  } else {
1297
- logger$3.debug(
1336
+ logger.debug(
1298
1337
  `[${strategy?.name}] - Pour cancelled for pour target ${pourTarget?.id}.`
1299
1338
  );
1300
1339
  onPourCancel?.();
1301
1340
  }
1302
1341
  }, [onPour, onBeforePour, onPourAbort, pourTarget, strategy, context]);
1303
1342
  const handleCancelPour = useCallback(async () => {
1304
- logger$3.debug(
1343
+ logger.debug(
1305
1344
  `[${strategy?.name}] - Pour initiate ended called for pour target ${pourTarget?.id}.`
1306
1345
  );
1307
1346
  const ignore = await strategy?.initiateEnded?.(pourTarget);
@@ -1310,7 +1349,7 @@ const usePourTarget = ({
1310
1349
  }
1311
1350
  }, [onPourCancel, pourTarget, strategy]);
1312
1351
  const forceCancelPour = useCallback(async () => {
1313
- logger$3.debug(`Force cancelling pour for pour target ${pourTarget?.id}.`);
1352
+ logger.debug(`Force cancelling pour for pour target ${pourTarget?.id}.`);
1314
1353
  await pourTarget?.cancelPour();
1315
1354
  onPourCancel?.();
1316
1355
  }, [onPourCancel, pourTarget]);
@@ -1338,98 +1377,6 @@ const usePourTarget = ({
1338
1377
  status: pourTarget
1339
1378
  };
1340
1379
  };
1341
- const logger$2 = KosLog.createLogger({
1342
- name: "TapOrHoldIntentStrategy",
1343
- group: "kos-hooks"
1344
- });
1345
- class TapOrHoldIntentStrategy {
1346
- intent;
1347
- name = "TapOrHoldIntentStrategy";
1348
- isHold = false;
1349
- disposer = null;
1350
- constructor(intent) {
1351
- this.intent = intent;
1352
- }
1353
- async initiate(model, intent) {
1354
- this.disposer = setTimeout(() => {
1355
- this.isHold = true;
1356
- }, 250);
1357
- if (model?.isPouring && !this.isHold) {
1358
- logger$2.debug(`additional tap detected. cancelling pour`);
1359
- await model.cancelPour();
1360
- return;
1361
- }
1362
- if (!model?.canPour) {
1363
- logger$2.debug(`${model?.id} cannot pour. Returning early.`);
1364
- return;
1365
- }
1366
- if (intent) {
1367
- logger$2.debug(`performing intent: ${intent}`);
1368
- await model?.performIntent(intent);
1369
- } else {
1370
- logger$2.debug("no intent provided. Returning early.");
1371
- }
1372
- }
1373
- async initiateEnded(nozzle) {
1374
- if (this.disposer) clearTimeout(this.disposer);
1375
- this.disposer = null;
1376
- if (!this.isHold) {
1377
- logger$2.debug("Tap detected. don't cancel and return.");
1378
- return true;
1379
- }
1380
- await nozzle?.cancelPour();
1381
- return false;
1382
- }
1383
- }
1384
- const logger$1 = KosLog.createLogger({
1385
- name: "TapToPourIntentStrategy",
1386
- group: "kos-hooks"
1387
- });
1388
- const TapToPourIntentStrategy = {
1389
- name: "TapToPourIntentStrategy",
1390
- async initiate(model, intent) {
1391
- if (model?.isPouring) {
1392
- logger$1.debug(`Nozzle ${model?.id} is already pouring. cancelling pour`);
1393
- await model.cancelPour();
1394
- return;
1395
- }
1396
- if (!model?.canPour) {
1397
- logger$1.debug(`Nozzle ${model?.id} cannot pour. Returning early.`);
1398
- return;
1399
- }
1400
- if (intent) {
1401
- logger$1.debug(`performing intent: ${intent}`);
1402
- await model?.performIntent(intent);
1403
- } else {
1404
- logger$1.debug("no intent provided. Returning early.");
1405
- }
1406
- },
1407
- async initiateEnded(_nozzle) {
1408
- return true;
1409
- }
1410
- };
1411
- const logger = KosLog.createLogger({
1412
- name: "HoldToPourStrategy",
1413
- group: "kos-hooks"
1414
- });
1415
- const TapToPourStrategy = {
1416
- name: "TapToPourStrategy",
1417
- async initiate(nozzle) {
1418
- if (nozzle?.isPouring) {
1419
- logger.debug(`Nozzle ${nozzle?.id} is already pouring. cancelling pour`);
1420
- await nozzle.cancelPour();
1421
- return;
1422
- }
1423
- if (!nozzle?.canPour) {
1424
- logger.debug(`Nozzle ${nozzle?.id} cannot pour. Returning early.`);
1425
- return;
1426
- }
1427
- await nozzle?.pour();
1428
- },
1429
- async initiateEnded(_nozzle) {
1430
- return true;
1431
- }
1432
- };
1433
1380
  const useGenericPour = (id, servicePathFactory, itemId, data) => {
1434
1381
  const modelId = id;
1435
1382
  const result = useKosModel({
@@ -1567,7 +1514,19 @@ function createDispenseKitContext() {
1567
1514
  }
1568
1515
  return ctx;
1569
1516
  };
1570
- return [useCuiKitContext, CuiKitContext.Provider];
1517
+ const useCuiPour = (options = {}) => {
1518
+ const kit = useContext(CuiKitContext);
1519
+ const gesture = usePressGesture({
1520
+ onPressed: () => void kit?.pour.press(options),
1521
+ onRelease: () => kit?.pour.release(options)
1522
+ });
1523
+ return {
1524
+ handlers: gesture.dom,
1525
+ start: async () => await kit?.pour.start(options) ?? false,
1526
+ cancel: () => kit?.pour.cancel()
1527
+ };
1528
+ };
1529
+ return [useCuiKitContext, CuiKitContext.Provider, useCuiPour];
1571
1530
  }
1572
1531
  function CuiKitWrapper({
1573
1532
  children,
@@ -1616,10 +1575,11 @@ function CuiKit({
1616
1575
  ) }) : null;
1617
1576
  }
1618
1577
  function initializeCuiKit(props) {
1619
- const [useCuiKitContext, DispenseKitProvider] = createDispenseKitContext();
1578
+ const [useCuiKitContext, DispenseKitProvider, useCuiPour] = createDispenseKitContext();
1620
1579
  return [
1621
1580
  useCuiKitContext,
1622
- CuiKit({ provider: DispenseKitProvider, props })
1581
+ CuiKit({ provider: DispenseKitProvider, props }),
1582
+ useCuiPour
1623
1583
  ];
1624
1584
  }
1625
1585
  const Holder = createContext(void 0);
@@ -1732,47 +1692,46 @@ const usePumpContext = () => {
1732
1692
  return context;
1733
1693
  };
1734
1694
  export {
1735
- usePourTarget as $,
1695
+ usePumpContext as $,
1736
1696
  AssemblyProvider as A,
1737
1697
  BoardContainerProvider as B,
1738
1698
  CuiKit as C,
1739
1699
  DISPENSE_GROUP_BEVERAGE as D,
1740
- useDefaultCuiKitLifecycle as E,
1741
- useDeviceAssembly as F,
1742
- useDeviceAssemblyContext as G,
1700
+ useDeviceAssembly as E,
1701
+ useDeviceAssemblyContext as F,
1702
+ useDispenseLifecycle as G,
1743
1703
  HoldToPourIntentStrategy as H,
1744
1704
  IngredientContainerProvider as I,
1745
- useDispenseLifecycle as J,
1746
- useFlavors as K,
1747
- useGenericPour as L,
1748
- useHolder as M,
1705
+ useFlavors as J,
1706
+ useGenericPour as K,
1707
+ useHolder as L,
1708
+ useHolderContainer as M,
1749
1709
  NozzleProvider as N,
1750
- useHolderContainer as O,
1751
- PourContext as P,
1752
- useHolderContainerContext as Q,
1753
- useHolderContext as R,
1754
- useIngredient as S,
1710
+ useHolderContainerContext as O,
1711
+ PumpProvider as P,
1712
+ useHolderContext as Q,
1713
+ useIngredient as R,
1714
+ useIngredientContainer as S,
1755
1715
  TapOrHoldIntentStrategy as T,
1756
- useIngredientContainer as U,
1757
- useIngredientContainerContext as V,
1758
- useIngredientContext as W,
1759
- useIngredientPour as X,
1760
- useNozzle as Y,
1761
- useNozzleContext as Z,
1762
- useNozzlePour as _,
1716
+ useIngredientContainerContext as U,
1717
+ useIngredientContext as V,
1718
+ useIngredientPour as W,
1719
+ useNozzle as X,
1720
+ useNozzleContext as Y,
1721
+ useNozzlePour as Z,
1722
+ usePourTarget as _,
1763
1723
  AvailabilityProvider as a,
1764
- usePumpContext as a0,
1765
- withAssembly as a1,
1766
- withBeverage as a2,
1767
- withBoard as a3,
1768
- withBoardContainer as a4,
1769
- withDeviceAssembly as a5,
1770
- withGenericPour as a6,
1771
- withHolder as a7,
1772
- withHolderContainer as a8,
1773
- withIngredient as a9,
1774
- withIngredientContainer as aa,
1775
- withNozzle as ab,
1724
+ withAssembly as a0,
1725
+ withBeverage as a1,
1726
+ withBoard as a2,
1727
+ withBoardContainer as a3,
1728
+ withDeviceAssembly as a4,
1729
+ withGenericPour as a5,
1730
+ withHolder as a6,
1731
+ withHolderContainer as a7,
1732
+ withIngredient as a8,
1733
+ withIngredientContainer as a9,
1734
+ withNozzle as aa,
1776
1735
  BoardProvider as b,
1777
1736
  CuiKitWrapper as c,
1778
1737
  DISPENSE_GROUP_BRAND as d,
@@ -1782,21 +1741,21 @@ export {
1782
1741
  HolderContainerProvider as h,
1783
1742
  HolderProvider as i,
1784
1743
  IngredientProvider as j,
1785
- PumpProvider as k,
1786
- TapToPourIntentStrategy as l,
1787
- TapToPourStrategy as m,
1788
- initializeCuiKit as n,
1789
- useAssemblyContext as o,
1790
- useAvailability as p,
1791
- useAvailabilityContext as q,
1792
- useBeverages as r,
1793
- useBoard as s,
1794
- useBoardContainer as t,
1744
+ TapToPourIntentStrategy as k,
1745
+ TapToPourStrategy as l,
1746
+ initializeCuiKit as m,
1747
+ useAssemblyContext as n,
1748
+ useAvailability as o,
1749
+ useAvailabilityContext as p,
1750
+ useBeverages as q,
1751
+ useBoard as r,
1752
+ useBoardContainer as s,
1753
+ useBoardContainerContext as t,
1795
1754
  useAssembly as u,
1796
- useBoardContainerContext as v,
1797
- useBoardContext as w,
1798
- useBrands as x,
1799
- useCuiKit as y,
1800
- useCuiKitTimers as z
1755
+ useBoardContext as v,
1756
+ useBrands as w,
1757
+ useCuiKit as x,
1758
+ useCuiKitTimers as y,
1759
+ useDefaultCuiKitLifecycle as z
1801
1760
  };
1802
- //# sourceMappingURL=pump-provider-BQmCKz7S.js.map
1761
+ //# sourceMappingURL=pump-provider-CPUsLke5.js.map