@flickfyi/flkr 0.0.182 → 0.0.185

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 (243) hide show
  1. package/dist/{api-client-CAg1b8Bh.js → api-client-nn4U_Vfn.js} +1 -1
  2. package/dist/{app-DpM5nhb9.js → app-COXGJhrt.js} +3 -3
  3. package/dist/{bundler-DNrDcqyk.js → bundler-CW4YC73e.js} +4 -2
  4. package/dist/cli.js +11 -11
  5. package/dist/{delegate-DcVye0KE.js → delegate-aUVluBjB.js} +2 -2
  6. package/dist/{generate-B1l1z_FZ.js → generate-BeL1QPDi.js} +1 -1
  7. package/dist/{preview-Dqn_Tq6K.js → preview-DTVM8Csb.js} +2 -2
  8. package/dist/{publish-BmDqO1xU.js → publish-BJG-s-w5.js} +4 -4
  9. package/dist/{pull-CO80DMn8.js → pull-B_Yfjpi2.js} +1 -1
  10. package/dist/{save-8crfOeo1.js → save-UrfgmK2-.js} +2 -2
  11. package/dist/{sdk-app-BXWrf_pf.js → sdk-app-BAxznAf9.js} +3 -3
  12. package/dist/{sdk-deploy-CaEonlvx.js → sdk-deploy-D1wgQxse.js} +3 -3
  13. package/dist/{sdk-generation-CF8ATbrL.js → sdk-generation-CLQ-QrVM.js} +1 -1
  14. package/dist/{sdk-project-CKV3U3u9.js → sdk-project-BaO0fqhW.js} +1 -1
  15. package/dist/{use-auth-B6nwU2rp.js → use-auth-CtM4_BAY.js} +1 -1
  16. package/node_modules/@flickfyi/biscuit/.turbo/turbo-build.log +4 -4
  17. package/node_modules/@flickfyi/core/README.md +19 -9
  18. package/node_modules/@flickfyi/core/dist/chunks/{default-CuxDsQoM.js → default-BTmKidHV.js} +1 -1
  19. package/node_modules/@flickfyi/core/dist/chunks/{default-BB6YexEH.cjs → default-JhTq5I_y.cjs} +1 -1
  20. package/node_modules/@flickfyi/core/dist/chunks/{define-CUJRqVKY.cjs → define-BKCRhpuY.cjs} +1 -1
  21. package/node_modules/@flickfyi/core/dist/chunks/{define-e_VqSs4M.js → define-DZXgUsy7.js} +5 -5
  22. package/node_modules/@flickfyi/core/dist/kowalski/catalog.cjs +1 -1
  23. package/node_modules/@flickfyi/core/dist/kowalski/catalog.js +728 -549
  24. package/node_modules/@flickfyi/core/dist/kowalski/index.cjs +5 -5
  25. package/node_modules/@flickfyi/core/dist/kowalski/index.js +4297 -3700
  26. package/node_modules/@flickfyi/core/dist/kowalski/schemas.cjs +1 -0
  27. package/node_modules/@flickfyi/core/dist/kowalski/schemas.js +637 -0
  28. package/node_modules/@flickfyi/core/dist/kowalski-catalog.css +516 -0
  29. package/node_modules/@flickfyi/core/dist/kowalski.css +10 -0
  30. package/node_modules/@flickfyi/core/dist/themes/athletic/athletic.cjs +1 -1
  31. package/node_modules/@flickfyi/core/dist/themes/athletic/athletic.js +1 -1
  32. package/node_modules/@flickfyi/core/dist/themes/compact/compact.cjs +1 -1
  33. package/node_modules/@flickfyi/core/dist/themes/compact/compact.js +1 -1
  34. package/node_modules/@flickfyi/core/dist/themes/default/default.cjs +1 -1
  35. package/node_modules/@flickfyi/core/dist/themes/default/default.js +1 -1
  36. package/node_modules/@flickfyi/core/dist/themes/editorial/editorial.cjs +1 -1
  37. package/node_modules/@flickfyi/core/dist/themes/editorial/editorial.js +1 -1
  38. package/node_modules/@flickfyi/core/dist/themes/handwritten/handwritten.cjs +1 -1
  39. package/node_modules/@flickfyi/core/dist/themes/handwritten/handwritten.js +1 -1
  40. package/node_modules/@flickfyi/core/dist/themes/index.cjs +1 -1
  41. package/node_modules/@flickfyi/core/dist/themes/index.js +1 -1
  42. package/node_modules/@flickfyi/core/dist/themes/kids/kids.cjs +1 -1
  43. package/node_modules/@flickfyi/core/dist/themes/kids/kids.js +1 -1
  44. package/node_modules/@flickfyi/core/dist/themes/rounded/rounded.cjs +1 -1
  45. package/node_modules/@flickfyi/core/dist/themes/rounded/rounded.js +1 -1
  46. package/node_modules/@flickfyi/core/dist/themes/technical/technical.cjs +1 -1
  47. package/node_modules/@flickfyi/core/dist/themes/technical/technical.js +1 -1
  48. package/node_modules/@flickfyi/core/dist-types/hooks/use-feature-store/index.d.ts +43 -0
  49. package/node_modules/@flickfyi/core/dist-types/kowalski/calculations.d.ts +57 -3
  50. package/node_modules/@flickfyi/core/dist-types/kowalski/calculator.d.ts +7 -6
  51. package/node_modules/@flickfyi/core/dist-types/kowalski/catalog.d.cts +524 -809
  52. package/node_modules/@flickfyi/core/dist-types/kowalski/catalog.d.ts +524 -809
  53. package/node_modules/@flickfyi/core/dist-types/kowalski/components/bill-split.d.ts +38 -0
  54. package/node_modules/@flickfyi/core/dist-types/kowalski/components/bookmark.d.ts +48 -0
  55. package/node_modules/@flickfyi/core/dist-types/kowalski/components/budget.d.ts +39 -0
  56. package/node_modules/@flickfyi/core/dist-types/kowalski/components/calculator.d.ts +62 -0
  57. package/node_modules/@flickfyi/core/dist-types/kowalski/components/checklist.d.ts +35 -0
  58. package/node_modules/@flickfyi/core/dist-types/kowalski/components/color-palette.d.ts +32 -0
  59. package/node_modules/@flickfyi/core/dist-types/kowalski/components/contact.d.ts +41 -0
  60. package/node_modules/@flickfyi/core/dist-types/kowalski/components/countdown.d.ts +34 -0
  61. package/node_modules/@flickfyi/core/dist-types/kowalski/components/event.d.ts +43 -0
  62. package/node_modules/@flickfyi/core/dist-types/kowalski/components/expense.d.ts +40 -0
  63. package/node_modules/@flickfyi/core/dist-types/kowalski/components/goal.d.ts +36 -0
  64. package/node_modules/@flickfyi/core/dist-types/kowalski/components/habit.d.ts +57 -0
  65. package/node_modules/@flickfyi/core/dist-types/kowalski/components/ledger.d.ts +43 -0
  66. package/node_modules/@flickfyi/core/dist-types/kowalski/components/note.d.ts +35 -0
  67. package/node_modules/@flickfyi/core/dist-types/kowalski/components/poll.d.ts +41 -0
  68. package/node_modules/@flickfyi/core/dist-types/kowalski/components/random-picker.d.ts +69 -0
  69. package/node_modules/@flickfyi/core/dist-types/kowalski/components/rating.d.ts +33 -0
  70. package/node_modules/@flickfyi/core/dist-types/kowalski/components/reminder.d.ts +48 -0
  71. package/node_modules/@flickfyi/core/dist-types/kowalski/components/rotation.d.ts +39 -0
  72. package/node_modules/@flickfyi/core/dist-types/kowalski/components/scoreboard.d.ts +37 -0
  73. package/node_modules/@flickfyi/core/dist-types/kowalski/components/shopping-list.d.ts +41 -0
  74. package/node_modules/@flickfyi/core/dist-types/kowalski/components/task-board.d.ts +39 -0
  75. package/node_modules/@flickfyi/core/dist-types/kowalski/components/time-zone.d.ts +34 -0
  76. package/node_modules/@flickfyi/core/dist-types/kowalski/components/timer.d.ts +43 -0
  77. package/node_modules/@flickfyi/core/dist-types/kowalski/components/trip.d.ts +61 -0
  78. package/node_modules/@flickfyi/core/dist-types/kowalski/components/unit-converter.d.ts +106 -0
  79. package/node_modules/@flickfyi/core/dist-types/kowalski/create-schemas.d.ts +6 -0
  80. package/node_modules/@flickfyi/core/dist-types/kowalski/date-time.d.ts +1 -1
  81. package/node_modules/@flickfyi/core/dist-types/kowalski/everyday.d.ts +28 -8
  82. package/node_modules/@flickfyi/core/dist-types/kowalski/feature-schema.d.ts +65 -0
  83. package/node_modules/@flickfyi/core/dist-types/kowalski/format.d.ts +4 -0
  84. package/node_modules/@flickfyi/core/dist-types/kowalski/fortune.d.ts +21 -0
  85. package/node_modules/@flickfyi/core/dist-types/kowalski/frame.d.ts +4 -4
  86. package/node_modules/@flickfyi/core/dist-types/kowalski/index.d.cts +31 -7
  87. package/node_modules/@flickfyi/core/dist-types/kowalski/index.d.ts +31 -7
  88. package/node_modules/@flickfyi/core/dist-types/kowalski/lesson.d.ts +89 -0
  89. package/node_modules/@flickfyi/core/dist-types/kowalski/recipe.d.ts +129 -8
  90. package/node_modules/@flickfyi/core/dist-types/kowalski/schemas.d.cts +4 -0
  91. package/node_modules/@flickfyi/core/dist-types/kowalski/schemas.d.ts +4 -0
  92. package/node_modules/@flickfyi/core/dist-types/kowalski/time-since.d.ts +34 -0
  93. package/node_modules/@flickfyi/core/examples/example-metadata.ts +19 -2
  94. package/node_modules/@flickfyi/core/examples/kowalski/bill-split/bill-split.stories.tsx +25 -6
  95. package/node_modules/@flickfyi/core/examples/kowalski/bill-split/bill-split.tsx +6 -12
  96. package/node_modules/@flickfyi/core/examples/kowalski/bookmark/bookmark.stories.tsx +22 -5
  97. package/node_modules/@flickfyi/core/examples/kowalski/bookmark/bookmark.tsx +6 -18
  98. package/node_modules/@flickfyi/core/examples/kowalski/budget/budget.stories.tsx +26 -5
  99. package/node_modules/@flickfyi/core/examples/kowalski/budget/budget.tsx +6 -21
  100. package/node_modules/@flickfyi/core/examples/kowalski/calculator/calculator.stories.tsx +18 -5
  101. package/node_modules/@flickfyi/core/examples/kowalski/calculator/calculator.tsx +6 -19
  102. package/node_modules/@flickfyi/core/examples/kowalski/checklist/checklist.stories.tsx +25 -5
  103. package/node_modules/@flickfyi/core/examples/kowalski/checklist/checklist.tsx +6 -21
  104. package/node_modules/@flickfyi/core/examples/kowalski/color-palette/color-palette.stories.tsx +19 -6
  105. package/node_modules/@flickfyi/core/examples/kowalski/color-palette/color-palette.tsx +6 -17
  106. package/node_modules/@flickfyi/core/examples/kowalski/contact/contact.stories.tsx +30 -5
  107. package/node_modules/@flickfyi/core/examples/kowalski/contact/contact.tsx +6 -18
  108. package/node_modules/@flickfyi/core/examples/kowalski/countdown/countdown.stories.tsx +22 -5
  109. package/node_modules/@flickfyi/core/examples/kowalski/countdown/countdown.tsx +6 -18
  110. package/node_modules/@flickfyi/core/examples/kowalski/event/event.stories.tsx +23 -5
  111. package/node_modules/@flickfyi/core/examples/kowalski/event/event.tsx +6 -19
  112. package/node_modules/@flickfyi/core/examples/kowalski/expense/expense.stories.tsx +23 -5
  113. package/node_modules/@flickfyi/core/examples/kowalski/expense/expense.tsx +6 -18
  114. package/node_modules/@flickfyi/core/examples/kowalski/fortune/fortune.stories.tsx +61 -0
  115. package/node_modules/@flickfyi/core/examples/kowalski/fortune/fortune.tsx +11 -0
  116. package/node_modules/@flickfyi/core/examples/kowalski/goal/goal.stories.tsx +18 -5
  117. package/node_modules/@flickfyi/core/examples/kowalski/goal/goal.tsx +3 -19
  118. package/node_modules/@flickfyi/core/examples/kowalski/habit/habit.stories.tsx +22 -5
  119. package/node_modules/@flickfyi/core/examples/kowalski/habit/habit.tsx +6 -18
  120. package/node_modules/@flickfyi/core/examples/kowalski/ledger/ledger.stories.tsx +25 -5
  121. package/node_modules/@flickfyi/core/examples/kowalski/ledger/ledger.tsx +6 -20
  122. package/node_modules/@flickfyi/core/examples/kowalski/lesson/lesson.stories.tsx +99 -0
  123. package/node_modules/@flickfyi/core/examples/kowalski/lesson/lesson.tsx +11 -0
  124. package/node_modules/@flickfyi/core/examples/kowalski/note/note.stories.tsx +21 -5
  125. package/node_modules/@flickfyi/core/examples/kowalski/note/note.tsx +3 -17
  126. package/node_modules/@flickfyi/core/examples/kowalski/poll/poll.stories.tsx +26 -5
  127. package/node_modules/@flickfyi/core/examples/kowalski/poll/poll.tsx +3 -21
  128. package/node_modules/@flickfyi/core/examples/kowalski/random-picker/random-picker.stories.tsx +37 -6
  129. package/node_modules/@flickfyi/core/examples/kowalski/random-picker/random-picker.tsx +6 -18
  130. package/node_modules/@flickfyi/core/examples/kowalski/rating/rating.stories.tsx +18 -5
  131. package/node_modules/@flickfyi/core/examples/kowalski/rating/rating.tsx +6 -14
  132. package/node_modules/@flickfyi/core/examples/kowalski/recipe/recipe.stories.tsx +117 -5
  133. package/node_modules/@flickfyi/core/examples/kowalski/recipe/recipe.tsx +6 -115
  134. package/node_modules/@flickfyi/core/examples/kowalski/reminder/reminder.stories.tsx +22 -5
  135. package/node_modules/@flickfyi/core/examples/kowalski/reminder/reminder.tsx +6 -18
  136. package/node_modules/@flickfyi/core/examples/kowalski/rotation/rotation.stories.tsx +26 -5
  137. package/node_modules/@flickfyi/core/examples/kowalski/rotation/rotation.tsx +6 -22
  138. package/node_modules/@flickfyi/core/examples/kowalski/scoreboard/scoreboard.stories.tsx +26 -5
  139. package/node_modules/@flickfyi/core/examples/kowalski/scoreboard/scoreboard.tsx +6 -21
  140. package/node_modules/@flickfyi/core/examples/kowalski/shopping-list/shopping-list.stories.tsx +28 -6
  141. package/node_modules/@flickfyi/core/examples/kowalski/shopping-list/shopping-list.tsx +6 -22
  142. package/node_modules/@flickfyi/core/examples/kowalski/task-board/task-board.stories.tsx +27 -6
  143. package/node_modules/@flickfyi/core/examples/kowalski/task-board/task-board.tsx +6 -22
  144. package/node_modules/@flickfyi/core/examples/kowalski/time-since/time-since.stories.tsx +33 -0
  145. package/node_modules/@flickfyi/core/examples/kowalski/time-since/time-since.tsx +12 -0
  146. package/node_modules/@flickfyi/core/examples/kowalski/time-zone/time-zone.stories.tsx +22 -6
  147. package/node_modules/@flickfyi/core/examples/kowalski/time-zone/time-zone.tsx +6 -17
  148. package/node_modules/@flickfyi/core/examples/kowalski/timer/timer.stories.tsx +18 -5
  149. package/node_modules/@flickfyi/core/examples/kowalski/timer/timer.tsx +6 -18
  150. package/node_modules/@flickfyi/core/examples/kowalski/trip/trip.stories.tsx +25 -5
  151. package/node_modules/@flickfyi/core/examples/kowalski/trip/trip.tsx +3 -21
  152. package/node_modules/@flickfyi/core/examples/kowalski/unit-converter/unit-converter.stories.tsx +19 -6
  153. package/node_modules/@flickfyi/core/examples/kowalski/unit-converter/unit-converter.tsx +6 -19
  154. package/node_modules/@flickfyi/core/examples/parrott/calculator/calculator.stories.tsx +10 -3
  155. package/node_modules/@flickfyi/core/examples/parrott/calculator/calculator.tsx +2 -13
  156. package/node_modules/@flickfyi/core/examples/parrott/checklist/checklist.stories.tsx +10 -3
  157. package/node_modules/@flickfyi/core/examples/parrott/checklist/checklist.tsx +0 -8
  158. package/node_modules/@flickfyi/core/examples/parrott/countdown/countdown.stories.tsx +10 -3
  159. package/node_modules/@flickfyi/core/examples/parrott/countdown/countdown.tsx +0 -8
  160. package/node_modules/@flickfyi/core/examples/parrott/counter/counter.stories.tsx +10 -3
  161. package/node_modules/@flickfyi/core/examples/parrott/counter/counter.tsx +0 -8
  162. package/node_modules/@flickfyi/core/examples/parrott/fortune/fortune.stories.tsx +10 -3
  163. package/node_modules/@flickfyi/core/examples/parrott/fortune/fortune.tsx +0 -8
  164. package/node_modules/@flickfyi/core/examples/parrott/grid/grid.stories.tsx +10 -3
  165. package/node_modules/@flickfyi/core/examples/parrott/grid/grid.tsx +4 -9
  166. package/node_modules/@flickfyi/core/examples/parrott/kale-smoothie/kale-smoothie.stories.tsx +10 -3
  167. package/node_modules/@flickfyi/core/examples/parrott/kale-smoothie/kale-smoothie.tsx +0 -8
  168. package/node_modules/@flickfyi/core/examples/parrott/list/list.stories.tsx +10 -3
  169. package/node_modules/@flickfyi/core/examples/parrott/list/list.tsx +0 -8
  170. package/node_modules/@flickfyi/core/examples/parrott/log/log.stories.tsx +10 -3
  171. package/node_modules/@flickfyi/core/examples/parrott/log/log.tsx +0 -8
  172. package/node_modules/@flickfyi/core/examples/parrott/timed-task/timed-task.stories.tsx +10 -3
  173. package/node_modules/@flickfyi/core/examples/parrott/timed-task/timed-task.tsx +0 -8
  174. package/node_modules/@flickfyi/core/examples/parrott/timer/timer.stories.tsx +10 -3
  175. package/node_modules/@flickfyi/core/examples/parrott/timer/timer.tsx +0 -8
  176. package/node_modules/@flickfyi/core/package.json +16 -3
  177. package/node_modules/@flickfyi/core/src/{kowalski/use-configured-feature.ts → hooks/use-configured-feature/index.ts} +1 -1
  178. package/node_modules/@flickfyi/core/src/{kowalski/use-feature-store.ts → hooks/use-feature-store/index.ts} +37 -12
  179. package/node_modules/@flickfyi/core/src/kowalski/README.md +13 -0
  180. package/node_modules/@flickfyi/core/src/kowalski/calculations.ts +36 -8
  181. package/node_modules/@flickfyi/core/src/kowalski/calculator.ts +15 -7
  182. package/node_modules/@flickfyi/core/src/kowalski/catalog.ts +110 -704
  183. package/node_modules/@flickfyi/core/src/kowalski/components/bill-split.tsx +284 -0
  184. package/node_modules/@flickfyi/core/src/kowalski/components/bookmark.tsx +347 -0
  185. package/node_modules/@flickfyi/core/src/kowalski/components/budget.tsx +169 -0
  186. package/node_modules/@flickfyi/core/src/kowalski/components/calculator.tsx +202 -0
  187. package/node_modules/@flickfyi/core/src/kowalski/components/checklist.tsx +119 -0
  188. package/node_modules/@flickfyi/core/src/kowalski/components/color-palette.tsx +302 -0
  189. package/node_modules/@flickfyi/core/src/kowalski/components/contact.tsx +247 -0
  190. package/node_modules/@flickfyi/core/src/kowalski/components/countdown.tsx +173 -0
  191. package/node_modules/@flickfyi/core/src/kowalski/components/event.tsx +260 -0
  192. package/node_modules/@flickfyi/core/src/kowalski/components/expense.tsx +257 -0
  193. package/node_modules/@flickfyi/core/src/kowalski/components/goal.tsx +182 -0
  194. package/node_modules/@flickfyi/core/src/kowalski/components/habit.tsx +272 -0
  195. package/node_modules/@flickfyi/core/src/kowalski/components/ledger.tsx +211 -0
  196. package/node_modules/@flickfyi/core/src/kowalski/components/note.tsx +188 -0
  197. package/node_modules/@flickfyi/core/src/kowalski/components/poll.tsx +242 -0
  198. package/node_modules/@flickfyi/core/src/kowalski/components/random-picker.tsx +308 -0
  199. package/node_modules/@flickfyi/core/src/kowalski/components/rating.tsx +112 -0
  200. package/node_modules/@flickfyi/core/src/kowalski/components/reminder.tsx +298 -0
  201. package/node_modules/@flickfyi/core/src/kowalski/components/rotation.tsx +146 -0
  202. package/node_modules/@flickfyi/core/src/kowalski/components/scoreboard.tsx +139 -0
  203. package/node_modules/@flickfyi/core/src/kowalski/components/shopping-list.tsx +144 -0
  204. package/node_modules/@flickfyi/core/src/kowalski/components/task-board.tsx +146 -0
  205. package/node_modules/@flickfyi/core/src/kowalski/components/time-zone.tsx +240 -0
  206. package/node_modules/@flickfyi/core/src/kowalski/components/timer.tsx +225 -0
  207. package/node_modules/@flickfyi/core/src/kowalski/components/trip.tsx +338 -0
  208. package/node_modules/@flickfyi/core/src/kowalski/components/unit-converter.tsx +285 -0
  209. package/node_modules/@flickfyi/core/src/kowalski/create-schemas.ts +8 -0
  210. package/node_modules/@flickfyi/core/src/kowalski/date-time.tsx +1 -1
  211. package/node_modules/@flickfyi/core/src/kowalski/everyday.tsx +1 -640
  212. package/node_modules/@flickfyi/core/src/kowalski/feature-schema.ts +84 -0
  213. package/node_modules/@flickfyi/core/src/kowalski/format.ts +29 -3
  214. package/node_modules/@flickfyi/core/src/kowalski/fortune.tsx +67 -0
  215. package/node_modules/@flickfyi/core/src/kowalski/frame.tsx +5 -6
  216. package/node_modules/@flickfyi/core/src/kowalski/index.ts +31 -22
  217. package/node_modules/@flickfyi/core/src/kowalski/lesson.tsx +564 -0
  218. package/node_modules/@flickfyi/core/src/kowalski/recipe.tsx +78 -37
  219. package/node_modules/@flickfyi/core/src/kowalski/schemas.ts +67 -0
  220. package/node_modules/@flickfyi/core/src/kowalski/stories/composition.tsx +22 -20
  221. package/node_modules/@flickfyi/core/src/kowalski/time-since.tsx +145 -0
  222. package/node_modules/@flickfyi/core/src/molecules/progress/progress.tsx +4 -1
  223. package/node_modules/@flickfyi/core/src/oklch.ts +1 -6
  224. package/node_modules/@flickfyi/core/src/parrott/theme.ts +3 -1
  225. package/node_modules/@flickfyi/core/src/themes/editorial/editorial.ts +6 -1
  226. package/node_modules/@flickfyi/core/src/themes/palette.ts +5 -5
  227. package/node_modules/@flickfyi/core/src/themes/stories/composition.tsx +11 -9
  228. package/node_modules/@flickfyi/core/src/themes/stories/gallery.tsx +7 -11
  229. package/node_modules/@flickfyi/core/tsgo.bun.lock +7 -7
  230. package/node_modules/@flickfyi/core/tsgo.package.json +1 -1
  231. package/package.json +2 -2
  232. package/node_modules/@flickfyi/core/dist-types/kowalski/clocks.d.ts +0 -4
  233. package/node_modules/@flickfyi/core/dist-types/kowalski/details.d.ts +0 -7
  234. package/node_modules/@flickfyi/core/dist-types/kowalski/productivity.d.ts +0 -5
  235. package/node_modules/@flickfyi/core/dist-types/kowalski/tools.d.ts +0 -7
  236. package/node_modules/@flickfyi/core/dist-types/kowalski/use-feature-store.d.ts +0 -15
  237. package/node_modules/@flickfyi/core/src/kowalski/clocks.tsx +0 -464
  238. package/node_modules/@flickfyi/core/src/kowalski/details.tsx +0 -1387
  239. package/node_modules/@flickfyi/core/src/kowalski/productivity.tsx +0 -575
  240. package/node_modules/@flickfyi/core/src/kowalski/tools.tsx +0 -1213
  241. /package/node_modules/@flickfyi/core/dist-types/{kowalski/use-clock.d.ts → hooks/use-clock/index.d.ts} +0 -0
  242. /package/node_modules/@flickfyi/core/dist-types/{kowalski/use-configured-feature.d.ts → hooks/use-configured-feature/index.d.ts} +0 -0
  243. /package/node_modules/@flickfyi/core/src/{kowalski/use-clock.ts → hooks/use-clock/index.ts} +0 -0
@@ -1,787 +1,193 @@
1
- import isURL from 'validator/lib/isURL.js'
2
- import { z } from 'zod/v4'
3
-
4
- /** A feature's store name; without one it is Kowalski<ExportName>. */
5
- export const kowalskiFeatureId = z
6
- .string()
7
- .regex(/^[A-Za-z][A-Za-z0-9]*$/)
8
- .optional()
9
- export const kowalskiScope = z.enum(['private', 'public']).default('private')
10
-
11
- /** Per-item store fields are `<prefix><item id>`; Florge checks their keys from this map. */
12
- export const entryPrefixes = {
13
- budget: 'spent_',
14
- checklist: 'completed_',
15
- habit: 'completed_',
16
- poll: 'vote_',
17
- recipe: 'step_',
18
- scoreboard: 'score_',
19
- shoppingList: 'got_',
20
- taskBoard: 'status_',
21
- } as const
22
-
23
- /** In JavaScript `Date#getUTCDay` order, so index 0 is Sunday. */
24
- export const weekdayNames = [
25
- 'sunday',
26
- 'monday',
27
- 'tuesday',
28
- 'wednesday',
29
- 'thursday',
30
- 'friday',
31
- 'saturday',
32
- ] as const
33
-
34
- /** Pure contracts shared by Core, Florge, and the catalog; no rendering imports. */
1
+ import { BillSplitProps } from '~/kowalski/components/bill-split'
2
+ import { BookmarkProps } from '~/kowalski/components/bookmark'
3
+ import { BudgetProps } from '~/kowalski/components/budget'
4
+ import { CalculatorProps } from '~/kowalski/components/calculator'
5
+ import { ChecklistProps } from '~/kowalski/components/checklist'
6
+ import { ColorPaletteProps } from '~/kowalski/components/color-palette'
7
+ import { ContactProps } from '~/kowalski/components/contact'
8
+ import { CountdownProps } from '~/kowalski/components/countdown'
9
+ import { EventProps } from '~/kowalski/components/event'
10
+ import { ExpenseProps } from '~/kowalski/components/expense'
11
+ import { GoalProps } from '~/kowalski/components/goal'
12
+ import { HabitProps } from '~/kowalski/components/habit'
13
+ import { LedgerProps } from '~/kowalski/components/ledger'
14
+ import { NoteProps } from '~/kowalski/components/note'
15
+ import { PollProps } from '~/kowalski/components/poll'
16
+ import { RandomPickerProps } from '~/kowalski/components/random-picker'
17
+ import { RatingProps } from '~/kowalski/components/rating'
18
+ import { ReminderProps } from '~/kowalski/components/reminder'
19
+ import { RotationProps } from '~/kowalski/components/rotation'
20
+ import { ScoreboardProps } from '~/kowalski/components/scoreboard'
21
+ import { ShoppingListProps } from '~/kowalski/components/shopping-list'
22
+ import { TaskBoardProps } from '~/kowalski/components/task-board'
23
+ import { TimeZoneProps } from '~/kowalski/components/time-zone'
24
+ import { TimerProps } from '~/kowalski/components/timer'
25
+ import { TripProps } from '~/kowalski/components/trip'
26
+ import { UnitConverterProps } from '~/kowalski/components/unit-converter'
27
+
28
+ import { FortuneProps } from './fortune'
29
+ import { LessonProps } from './lesson'
30
+ import { RecipeProps } from './recipe'
31
+ import { TimeSinceProps } from './time-since'
32
+
33
+ export { unitDefinitions } from './calculations'
34
+ export {
35
+ type KowalskiComponent,
36
+ kowalskiComponentSchema,
37
+ kowalskiFeatureId,
38
+ kowalskiScope,
39
+ } from './feature-schema'
40
+ export { FortuneData } from './fortune'
41
+ export { LessonData } from './lesson'
42
+ export { RecipeData } from './recipe'
43
+ export { TimeSinceData } from './time-since'
44
+ export { BillSplitData } from '~/kowalski/components/bill-split'
45
+ export { BookmarkData, webAddressOptions } from '~/kowalski/components/bookmark'
46
+ export { BudgetData } from '~/kowalski/components/budget'
47
+ export { CalculatorData } from '~/kowalski/components/calculator'
48
+ export { ChecklistData } from '~/kowalski/components/checklist'
49
+ export { ColorPaletteData } from '~/kowalski/components/color-palette'
50
+ export { ContactData } from '~/kowalski/components/contact'
51
+ export { CountdownData } from '~/kowalski/components/countdown'
52
+ export { EventData } from '~/kowalski/components/event'
53
+ export { ExpenseData } from '~/kowalski/components/expense'
54
+ export { GoalData } from '~/kowalski/components/goal'
55
+ export { HabitData } from '~/kowalski/components/habit'
56
+ export { LedgerData } from '~/kowalski/components/ledger'
57
+ export { NoteData } from '~/kowalski/components/note'
58
+ export { PollData, pollVoterSchema } from '~/kowalski/components/poll'
59
+ export { RandomPickerData } from '~/kowalski/components/random-picker'
60
+ export { RatingData } from '~/kowalski/components/rating'
61
+ export { ReminderData } from '~/kowalski/components/reminder'
62
+ export { RotationData } from '~/kowalski/components/rotation'
63
+ export { ScoreboardData } from '~/kowalski/components/scoreboard'
64
+ export { ShoppingListData } from '~/kowalski/components/shopping-list'
65
+ export { TaskBoardData } from '~/kowalski/components/task-board'
66
+ export { TimeZoneData } from '~/kowalski/components/time-zone'
67
+ export { TimerData } from '~/kowalski/components/timer'
68
+ export { TripData } from '~/kowalski/components/trip'
69
+ export { UnitConverterData } from '~/kowalski/components/unit-converter'
70
+
71
+ /** Contracts shared by Core, Florge, and the catalog. */
35
72
  export const kowalskiCatalog = {
36
73
  billSplit: {
37
- description:
38
- 'Split a bill equally with an optional tip, rounding in the selected currency.',
39
74
  exportName: 'BillSplit',
40
- props: featureProps({
41
- currency: currency(),
42
- people: z.number().int().min(1).max(1000),
43
- tipPercent: z.number().min(0).max(100).default(0),
44
- title: title('Split the bill'),
45
- total: z.number().min(0).max(1e12),
46
- }),
47
- storeSchema: store({
48
- people: z.number().int().min(1).max(1000).default(1),
49
- tipPercent: z.number().min(0).max(100).default(0),
50
- total: z.number().min(0).max(1e12).default(0),
51
- }),
75
+ props: BillSplitProps,
52
76
  },
53
77
  bookmark: {
54
- description: 'Display, edit, and retain a web bookmark. No implicit metadata fetch.',
55
78
  exportName: 'Bookmark',
56
- props: featureProps({
57
- note: z.string().max(10_000).default(''),
58
- title: title(),
59
- url: webAddress(),
60
- }),
61
- storeSchema: store({
62
- note: replacement(z.string().max(10_000).default('')),
63
- title: replacement(z.string().max(160).default('')),
64
- url: replacement(webAddress().nullable().default(null)),
65
- }),
79
+ props: BookmarkProps,
66
80
  },
67
81
  budget: {
68
- description:
69
- 'Track spending against category limits for one budget period. No bank connection or payments.',
70
82
  exportName: 'Budget',
71
- props: featureProps({
72
- categories: identifiedList(
73
- { label: z.string().min(1).max(80), limit: z.number().positive().max(1e12) },
74
- 12
75
- ),
76
- currency: currency(),
77
- title: title('Budget'),
78
- }),
79
- storeSchema: entries(entryPrefixes.budget, z.number().min(0).max(1e12), {}),
83
+ props: BudgetProps,
80
84
  },
81
85
  calculator: {
82
- description:
83
- 'A persistent keypad calculator with chained arithmetic, decimals, sign, percent, and repeated equals. Supports +, -, *, /. No executable expression strings.',
84
86
  exportName: 'Calculator',
85
- props: featureProps({
86
- left: z.number().default(0),
87
- operator: z.enum(['+', '-', '*', '/']).default('+'),
88
- right: z.number().default(0),
89
- title: title('Calculate'),
90
- }),
91
- storeSchema: store({
92
- calculation: z
93
- .object({
94
- entry: z
95
- .string()
96
- .max(40)
97
- .regex(/^(?:-?\d+(?:\.\d*)?(?:e[+-]?\d+)?|Error)$/),
98
- left: z.number(),
99
- operator: z.enum(['+', '-', '*', '/']),
100
- overwrite: z.boolean(),
101
- phase: z.enum(['left', 'operator', 'right', 'result', 'error']),
102
- right: z.number(),
103
- })
104
- .refine(
105
- calculation =>
106
- calculation.phase === 'error'
107
- ? calculation.entry === 'Error'
108
- : calculation.entry !== 'Error' &&
109
- Number.isFinite(Number(calculation.entry)),
110
- 'Calculator entry must match its phase and represent a finite number.'
111
- )
112
- .default({
113
- entry: '0',
114
- left: 0,
115
- operator: '+',
116
- overwrite: false,
117
- phase: 'left',
118
- right: 0,
119
- }),
120
- }),
87
+ props: CalculatorProps,
121
88
  },
122
89
  checklist: {
123
- description:
124
- 'A persistent checklist with independent completion and progress. No external actions.',
125
90
  exportName: 'Checklist',
126
- props: featureProps({
127
- items: identifiedList({ label: z.string().min(1).max(500) }, 100),
128
- title: title(),
129
- }),
130
- storeSchema: entries(entryPrefixes.checklist, z.boolean(), {}),
91
+ props: ChecklistProps,
131
92
  },
132
93
  colorPalette: {
133
- description: 'Choose and retain an sRGB color and display matching shades.',
134
94
  exportName: 'ColorPalette',
135
- props: featureProps({
136
- color: z.string().regex(/^#[\da-fA-F]{6}$/),
137
- title: title('Palette'),
138
- }),
139
- storeSchema: store({
140
- color: replacement(
141
- z
142
- .string()
143
- .regex(/^#[\da-fA-F]{6}$/)
144
- .default('#6366f1')
145
- ),
146
- }),
95
+ props: ColorPaletteProps,
147
96
  },
148
97
  contact: {
149
- description:
150
- 'Display, edit, and retain a contact. Does not insert into the address book.',
151
98
  exportName: 'Contact',
152
- props: featureProps({
153
- email: z.email().optional(),
154
- name: z.string().min(1).max(160),
155
- phone: z.string().min(1).max(80).optional(),
156
- }),
157
- storeSchema: store({
158
- email: replacement(z.email().nullable().default(null)),
159
- name: replacement(z.string().max(160).default('')),
160
- phone: replacement(z.string().min(1).max(80).nullable().default(null)),
161
- }),
99
+ props: ContactProps,
162
100
  },
163
101
  countdown: {
164
- description:
165
- 'Count down to an explicit instant. Resolve missing dates before instantiation.',
166
102
  exportName: 'Countdown',
167
- props: featureProps({
168
- target: z.iso.datetime({ offset: true }),
169
- timeZone: timeZone().default('UTC'),
170
- title: title(),
171
- }),
172
- storeSchema: store({
173
- target: replacement(z.iso.datetime({ offset: true }).nullable().default(null)),
174
- }),
103
+ props: CountdownProps,
175
104
  },
176
105
  event: {
177
- description:
178
- 'Save and edit event details in the app. Does not create a calendar event.',
179
106
  exportName: 'Event',
180
- props: featureProps({
181
- location: z.string().max(500).default(''),
182
- startsAt: z.iso.datetime({ offset: true }).nullable().default(null),
183
- timeZone: timeZone().default('UTC'),
184
- title: title(),
185
- }),
186
- storeSchema: store({
187
- location: replacement(z.string().max(500).default('')),
188
- startsAt: replacement(z.iso.datetime({ offset: true }).nullable().default(null)),
189
- title: replacement(z.string().max(160).default('')),
190
- }),
107
+ props: EventProps,
191
108
  },
192
109
  expense: {
193
- description:
194
- 'Edit and retain one expense. No payments, bank connection, or exchange-rate lookup.',
195
110
  exportName: 'Expense',
196
- props: featureProps({
197
- amount: z.number().min(0).max(1e12),
198
- category: z.string().max(80).default('Other'),
199
- currency: currency(),
200
- title: title(),
201
- }),
202
- storeSchema: store({
203
- amount: z.number().min(0).max(1e12).default(0),
204
- category: replacement(z.string().max(80).default('Other')),
205
- title: replacement(z.string().max(160).default('')),
206
- }),
111
+ props: ExpenseProps,
112
+ },
113
+ fortune: {
114
+ exportName: 'Fortune',
115
+ props: FortuneProps,
207
116
  },
208
117
  goal: {
209
- description:
210
- 'A personal goal with editable progress, target, and a fixed increment. Not a distributed counter.',
211
118
  exportName: 'Goal',
212
- props: featureProps({
213
- progress: z.number().min(0).max(1e12).default(0),
214
- step: z.number().positive().max(1e9).default(1),
215
- target: z.number().positive().max(1e12),
216
- title: title(),
217
- unit: z.string().max(40).default(''),
218
- }),
219
- storeSchema: store({ progress: z.number().min(0).default(0) }),
119
+ props: GoalProps,
220
120
  },
221
121
  habit: {
222
- description:
223
- 'Track a habit by local date and edit its weekday schedule. No notifications.',
224
122
  exportName: 'Habit',
225
- props: featureProps({
226
- timeZone: timeZone().default('UTC'),
227
- title: title(),
228
- weekdays: weekdays(),
229
- }),
230
- storeSchema: entries(entryPrefixes.habit, z.boolean(), { weekdays: weekdays() }),
123
+ props: HabitProps,
231
124
  },
232
125
  ledger: {
233
- description:
234
- 'A running tab of shared costs between two people, split evenly, with settle up. No payments.',
235
126
  exportName: 'Ledger',
236
- props: featureProps({
237
- currency: currency(),
238
- people: identifiedList({ label: z.string().min(1).max(80) }, 2, 2),
239
- title: title('Shared tab'),
240
- }),
241
- storeSchema: store({
242
- entries: z
243
- .array(
244
- z.strictObject({
245
- amount: z.number().positive().max(1e12),
246
- id: itemId(),
247
- label: z.string().max(160),
248
- paidBy: itemId(),
249
- })
250
- )
251
- .max(200)
252
- .default([]),
253
- }),
127
+ props: LedgerProps,
128
+ },
129
+ lesson: {
130
+ exportName: 'Lesson',
131
+ props: LessonProps,
254
132
  },
255
133
  note: {
256
- description: 'An editable persistent note. Plain text; no HTML or code execution.',
257
134
  exportName: 'Note',
258
- props: featureProps({
259
- body: z.string().max(20_000),
260
- title: z.string().max(160),
261
- }),
262
- storeSchema: store({
263
- body: replacement(z.string().max(20_000).default('')),
264
- title: replacement(z.string().max(160).default('')),
265
- }),
135
+ props: NoteProps,
266
136
  },
267
137
  poll: {
268
138
  exportName: 'Poll',
269
- description:
270
- 'Cast or change a vote and derive totals from votes. Shared voting only when explicitly requested.',
271
- props: featureProps({
272
- options: identifiedList({ label: z.string().min(1).max(160) }, 12, 2),
273
- question: z.string().min(1).max(500),
274
- shared: z.boolean().default(false),
275
- }),
276
- // Each vote_<voter> holds an option id.
277
- storeSchema: entries(entryPrefixes.poll, itemId(), {}),
139
+ props: PollProps,
278
140
  },
279
141
  randomPicker: {
280
- description:
281
- 'Flip a coin, roll a die, or pick from a bounded integer range or list. Retains the last result.',
282
142
  exportName: 'RandomPicker',
283
- props: z.discriminatedUnion('mode', [
284
- featureProps({ mode: z.literal('coin'), title: title('Pick one') }),
285
- featureProps({ mode: z.literal('dice'), title: title('Pick one') }),
286
- featureProps({
287
- maximum: z.number().int().min(-1e9).max(1e9),
288
- minimum: z.number().int().min(-1e9).max(1e9),
289
- mode: z.literal('range'),
290
- title: title('Pick one'),
291
- }).refine(value => value.minimum <= value.maximum, {
292
- message: 'Minimum cannot exceed maximum.',
293
- path: ['maximum'],
294
- }),
295
- featureProps({
296
- mode: z.literal('list'),
297
- options: z.array(z.string().min(1).max(160)).min(1).max(100),
298
- title: title('Pick one'),
299
- }),
300
- ]),
301
- // The last pick, with the choices it was drawn from so a changed picker drops it.
302
- storeSchema: store({
303
- result: z
304
- .strictObject({
305
- domain: pickerDomain(),
306
- value: z.union([z.number().int(), z.string().max(160)]),
307
- })
308
- .nullable()
309
- .default(null),
310
- }),
143
+ props: RandomPickerProps,
311
144
  },
312
145
  rating: {
313
- description: 'Rate one thing from one to five stars and keep a short note about it.',
314
146
  exportName: 'Rating',
315
- props: featureProps({
316
- subject: z.string().min(1).max(160),
317
- title: title('Your rating'),
318
- }),
319
- storeSchema: store({
320
- note: replacement(z.string().max(2000).default('')),
321
- stars: z.number().int().min(0).max(5).default(0),
322
- }),
147
+ props: RatingProps,
323
148
  },
324
149
  recipe: {
325
- description:
326
- 'Cook a recipe whose steps follow the Recipe Graph Format (rgf/0-draft): each step uses ingredients or earlier step outputs, waits on the steps in after, and may carry a duration, doneness cue, and attention. Ingredients carry a numeric amount and unit, and meta.servings is a number, so amounts scale with servings. Shows running timers, the current step, and the next few. No nutrition or shopping lookup.',
327
150
  exportName: 'Recipe',
328
- props: featureProps({
329
- ingredients: identifiedList(
330
- {
331
- amount: z.number().positive().max(1e6).optional(),
332
- label: z.string().min(1).max(160),
333
- notes: z.array(z.string().max(160)).max(10).optional(),
334
- unit: z.string().max(40).optional(),
335
- },
336
- 60
337
- ),
338
- servings: z.number().int().min(1).max(100).optional(),
339
- // Steps follow RGF (rgf/0-draft): uses, outputs, and after form the dependency graph.
340
- steps: z
341
- .array(
342
- z.strictObject({
343
- after: z.array(itemId()).max(60).optional(),
344
- attention: z.enum(['active', 'passive']).optional(),
345
- doneness: z.string().max(200).optional(),
346
- duration: z
347
- .strictObject({
348
- maxMinutes: z.number().nonnegative().max(10_080).optional(),
349
- minMinutes: z.number().nonnegative().max(10_080).optional(),
350
- raw: z.string().min(1).max(80),
351
- })
352
- .refine(
353
- duration =>
354
- duration.minMinutes === undefined ||
355
- duration.maxMinutes === undefined ||
356
- duration.minMinutes <= duration.maxMinutes,
357
- 'minMinutes cannot exceed maxMinutes.'
358
- )
359
- .optional(),
360
- equipment: z.array(z.string().min(1).max(160)).max(20).optional(),
361
- id: itemId(),
362
- instruction: z.string().min(1).max(500),
363
- kind: z.enum(['setup', 'transform', 'wait', 'serve']).optional(),
364
- label: z.string().max(80).optional(),
365
- outputs: z
366
- .array(z.strictObject({ id: itemId(), name: z.string().max(160).optional() }))
367
- .max(10)
368
- .optional(),
369
- temperature: z.string().min(1).max(80).optional(),
370
- uses: z
371
- .array(
372
- z.strictObject({
373
- id: itemId(),
374
- portion: z.string().max(80).optional(),
375
- source: z.discriminatedUnion('kind', [
376
- z.strictObject({ ingredientId: itemId(), kind: z.literal('ingredient') }),
377
- z.strictObject({ kind: z.literal('output'), outputId: itemId() }),
378
- ]),
379
- })
380
- )
381
- .max(30)
382
- .default([]),
383
- })
384
- )
385
- .min(1)
386
- .max(60),
387
- title: title(),
388
- yield: z.string().max(160).optional(),
389
- }).superRefine((recipe, context) => {
390
- // Every edge points at an earlier step, so the graph is acyclic.
391
- const ingredients = new Set(recipe.ingredients.map(ingredient => ingredient.id))
392
- const steps = new Set<string>()
393
- const outputs = new Set<string>()
394
- for (const step of recipe.steps) {
395
- const valid =
396
- !steps.has(step.id) &&
397
- (step.after ?? []).every(id => steps.has(id)) &&
398
- step.uses.every(use =>
399
- use.source.kind === 'ingredient'
400
- ? ingredients.has(use.source.ingredientId)
401
- : outputs.has(use.source.outputId)
402
- )
403
- if (!valid) {
404
- context.addIssue({
405
- code: 'custom',
406
- message: `Step ${step.id} needs a unique ID and can only use ingredients and earlier steps.`,
407
- })
408
- }
409
- steps.add(step.id)
410
- for (const output of step.outputs ?? []) {
411
- if (outputs.has(output.id)) {
412
- context.addIssue({ code: 'custom', message: 'Output IDs must be unique.' })
413
- }
414
- outputs.add(output.id)
415
- }
416
- }
417
- }),
418
- // Each step_<id> holds whether the step is done and when its timer ends.
419
- storeSchema: entries(
420
- entryPrefixes.recipe,
421
- z.strictObject({ done: z.boolean(), endsAt: z.number().nullable() }),
422
- {
423
- cooking: z.boolean().default(false),
424
- servings: z.number().int().min(1).max(100).default(1),
425
- }
426
- ),
151
+ props: RecipeProps,
427
152
  },
428
153
  reminder: {
429
- description:
430
- 'Complete, reopen, and edit an in-app reminder. Does not schedule notifications.',
431
154
  exportName: 'Reminder',
432
- props: featureProps({
433
- dueAt: z.iso.datetime({ offset: true }).nullable().default(null),
434
- recurrence: z.enum(['none', 'daily', 'weekly']).default('none'),
435
- timeZone: timeZone().optional(),
436
- title: z.string().min(1).max(500),
437
- }),
438
- storeSchema: store({
439
- completedAt: z.number().nullable().default(null),
440
- dueAt: replacement(z.iso.datetime({ offset: true }).nullable().default(null)),
441
- title: replacement(z.string().max(500).default('')),
442
- }),
155
+ props: ReminderProps,
443
156
  },
444
157
  rotation: {
445
- description:
446
- 'Take turns through a fixed group in order and pass the turn on when done.',
447
158
  exportName: 'Rotation',
448
- props: featureProps({
449
- people: identifiedList({ label: z.string().min(1).max(80) }, 20, 2),
450
- task: z.string().min(1).max(160),
451
- title: title('Whose turn'),
452
- }),
453
- // The person whose turn it is; null means the first person.
454
- storeSchema: store({
455
- completed: z.number().int().min(0).default(0),
456
- turn: itemId().nullable().default(null),
457
- }),
159
+ props: RotationProps,
458
160
  },
459
161
  scoreboard: {
460
- description:
461
- 'Keep score for a few players with a fixed step. Not a distributed counter or a league.',
462
162
  exportName: 'Scoreboard',
463
- props: featureProps({
464
- players: identifiedList({ label: z.string().min(1).max(80) }, 12, 2),
465
- step: z.number().int().positive().max(1000).default(1),
466
- title: title('Scores'),
467
- }),
468
- storeSchema: entries(entryPrefixes.scoreboard, z.number().int(), {}),
163
+ props: ScoreboardProps,
469
164
  },
470
165
  shoppingList: {
471
- description:
472
- 'Check items off a shopping list with optional prices and a running cart total. No ordering.',
473
166
  exportName: 'ShoppingList',
474
- props: featureProps({
475
- currency: currency(),
476
- items: identifiedList(
477
- {
478
- label: z.string().min(1).max(160),
479
- price: z.number().min(0).max(1e9).optional(),
480
- quantity: z.number().int().min(1).max(999).default(1),
481
- },
482
- 100
483
- ),
484
- title: title('Shopping list'),
485
- }),
486
- storeSchema: entries(entryPrefixes.shoppingList, z.boolean(), {}),
167
+ props: ShoppingListProps,
487
168
  },
488
169
  taskBoard: {
489
- description:
490
- 'Move tasks between To do, Doing, and Done. No assignees, dates, or sync.',
491
170
  exportName: 'TaskBoard',
492
- props: featureProps({
493
- tasks: identifiedList({ label: z.string().min(1).max(500) }, 50),
494
- title: title('Tasks'),
495
- }),
496
- storeSchema: entries(entryPrefixes.taskBoard, z.enum(['todo', 'doing', 'done']), {}),
171
+ props: TaskBoardProps,
172
+ },
173
+ timeSince: {
174
+ exportName: 'TimeSince',
175
+ props: TimeSinceProps,
497
176
  },
498
177
  timeZone: {
499
- description:
500
- 'Compare local times in named time zones, live or at an explicit instant.',
501
178
  exportName: 'TimeZone',
502
- props: featureProps({
503
- at: z.iso.datetime({ offset: true }).nullable().default(null),
504
- title: title('World clock'),
505
- zones: z.array(timeZone()).min(2).max(6),
506
- }),
507
- storeSchema: store({
508
- at: replacement(z.iso.datetime({ offset: true }).nullable().default(null)),
509
- }),
179
+ props: TimeZoneProps,
510
180
  },
511
181
  timer: {
512
- description:
513
- 'Countdown, focus, break, or stopwatch. Start, pause, resume, reset; no background alarm.',
514
182
  exportName: 'Timer',
515
- props: featureProps({
516
- durationSeconds: z.number().int().min(1).max(604_800).default(300),
517
- mode: z.enum(['countdown', 'focus', 'break', 'stopwatch']).default('countdown'),
518
- title: title('Timer'),
519
- }),
520
- storeSchema: store({
521
- elapsedSeconds: z.number().min(0).default(0),
522
- startedAt: z.number().nullable().default(null),
523
- }),
183
+ props: TimerProps,
524
184
  },
525
185
  trip: {
526
- description: 'Edit and retain trip details. No bookings or itinerary retrieval.',
527
186
  exportName: 'Trip',
528
- props: featureProps({
529
- destination: z.string().min(1).max(160),
530
- endDate: z.iso.date().nullable().default(null),
531
- origin: z.string().min(1).max(160),
532
- startDate: z.iso.date().nullable().default(null),
533
- title: title('Trip'),
534
- transport: z.enum(['car', 'train', 'plane', 'walk', 'other']).default('other'),
535
- }).refine(
536
- value => !value.startDate || !value.endDate || value.endDate >= value.startDate,
537
- {
538
- message: 'The trip cannot end before it starts.',
539
- path: ['endDate'],
540
- }
541
- ),
542
- storeSchema: store({
543
- destination: replacement(z.string().max(160).default('')),
544
- endDate: replacement(z.iso.date().nullable().default(null)),
545
- origin: replacement(z.string().max(160).default('')),
546
- startDate: replacement(z.iso.date().nullable().default(null)),
547
- }).refine(
548
- value =>
549
- !value.startDate.value ||
550
- !value.endDate.value ||
551
- value.endDate.value >= value.startDate.value,
552
- 'The trip cannot end before it starts.'
553
- ),
187
+ props: TripProps,
554
188
  },
555
189
  unitConverter: {
556
- description:
557
- 'Convert compatible length, mass, or temperature units deterministically.',
558
190
  exportName: 'UnitConverter',
559
- props: featureProps({
560
- from: unit(),
561
- title: title('Convert'),
562
- to: unit(),
563
- value: z.number(),
564
- }).refine(
565
- ({ from, to }) => unitDefinitions[from].dimension === unitDefinitions[to].dimension,
566
- {
567
- message: 'Source and destination units must measure the same dimension.',
568
- path: ['to'],
569
- }
570
- ),
571
- storeSchema: store({
572
- from: replacement(unit().default('km')),
573
- to: replacement(unit().default('mi')),
574
- value: z.number().default(0),
575
- }).refine(
576
- ({ from, to }) =>
577
- unitDefinitions[from.value].dimension === unitDefinitions[to.value].dimension,
578
- 'Incompatible units.'
579
- ),
191
+ props: UnitConverterProps,
580
192
  },
581
193
  }
582
-
583
- export type KowalskiComponent = keyof typeof kowalskiCatalog
584
- export const kowalskiComponentSchema = z.enum([
585
- 'checklist',
586
- 'timer',
587
- 'habit',
588
- 'goal',
589
- 'poll',
590
- 'event',
591
- 'reminder',
592
- 'trip',
593
- 'countdown',
594
- 'timeZone',
595
- 'colorPalette',
596
- 'billSplit',
597
- 'expense',
598
- 'unitConverter',
599
- 'calculator',
600
- 'randomPicker',
601
- 'contact',
602
- 'bookmark',
603
- 'note',
604
- 'budget',
605
- 'scoreboard',
606
- 'taskBoard',
607
- 'recipe',
608
- 'rotation',
609
- 'shoppingList',
610
- 'rating',
611
- 'ledger',
612
- ])
613
- export type KowalskiInput<K extends KowalskiComponent> = z.input<
614
- (typeof kowalskiCatalog)[K]['props']
615
- >
616
- export type KowalskiProps<K extends KowalskiComponent> = z.output<
617
- (typeof kowalskiCatalog)[K]['props']
618
- >
619
- export type KowalskiState<K extends KowalskiComponent> = z.output<
620
- (typeof kowalskiCatalog)[K]['storeSchema']
621
- >
622
- export type PickerDomain = NonNullable<KowalskiState<'randomPicker'>['result']>['domain']
623
- export type Weekday = (typeof weekdayNames)[number]
624
-
625
- export const pollVoterSchema = z.object({
626
- configuration: z.string().default(''),
627
- voter: z.string().min(1),
628
- })
629
-
630
- export const webAddressOptions = {
631
- max_allowed_length: 2048,
632
- protocols: ['http', 'https'],
633
- require_host: true,
634
- require_protocol: true,
635
- require_tld: false,
636
- require_valid_protocol: true,
637
- }
638
-
639
- /** SI relationships; temperature offsets are applied before scaling. */
640
- export const unitDefinitions = {
641
- c: { dimension: 'temperature', factor: 1, offset: 0 },
642
- f: { dimension: 'temperature', factor: 5 / 9, offset: -32 },
643
- ft: { dimension: 'length', factor: 0.3048, offset: 0 },
644
- g: { dimension: 'mass', factor: 0.001, offset: 0 },
645
- k: { dimension: 'temperature', factor: 1, offset: -273.15 },
646
- kg: { dimension: 'mass', factor: 1, offset: 0 },
647
- km: { dimension: 'length', factor: 1000, offset: 0 },
648
- lb: { dimension: 'mass', factor: 0.45359237, offset: 0 },
649
- m: { dimension: 'length', factor: 1, offset: 0 },
650
- mi: { dimension: 'length', factor: 1609.344, offset: 0 },
651
- }
652
-
653
- function featureProps<Shape extends z.ZodRawShape>(shape: Shape) {
654
- return z.strictObject({
655
- id: kowalskiFeatureId,
656
- revision: z.number().int().min(0).default(0),
657
- scope: kowalskiScope,
658
- ...shape,
659
- })
660
- }
661
-
662
- function currency() {
663
- return z
664
- .string()
665
- .regex(/^[A-Z]{3}$/)
666
- .default('USD')
667
- }
668
-
669
- /**
670
- * Per-item state as top-level `<prefix><id>` fields, which Quantum patches independently.
671
- * The template-literal record types them by prefix, so they never collide with the named
672
- * fields; any other key is rejected.
673
- */
674
- function entries<
675
- Prefix extends string,
676
- Value extends z.ZodType,
677
- Shape extends z.ZodRawShape,
678
- >(prefix: Prefix, value: Value, shape: Shape) {
679
- const named = store(shape)
680
- const keys = new Set(Object.keys(named.shape))
681
- return z
682
- .intersection(named.loose(), z.looseRecord(z.templateLiteral([prefix, z.string()]), value))
683
- .refine(
684
- state => Object.keys(state).every(key => keys.has(key) || key.startsWith(prefix)),
685
- `Item fields must start with ${prefix}.`
686
- )
687
- }
688
-
689
- /** Items with required stable ids, which key their saved state. */
690
- function identifiedList<Shape extends z.ZodRawShape>(shape: Shape, max: number, min = 1) {
691
- return z
692
- .array(z.strictObject(shape).extend({ id: itemId() }))
693
- .min(min)
694
- .max(max)
695
- .refine(uniqueIds, 'IDs must be unique.')
696
- }
697
-
698
- /** Free-form ids; they key Quantum state, so __proto__ is out. */
699
- function itemId() {
700
- return z
701
- .string()
702
- .min(1)
703
- .max(80)
704
- .refine(id => id !== '__proto__')
705
- }
706
-
707
- /**
708
- * The choices a pick was drawn from. A plain union of strict variants (anyOf in JSON
709
- * Schema) stays representable in the generated Quantum store source; oneOf does not.
710
- */
711
- function pickerDomain() {
712
- return z.union([
713
- z.strictObject({ mode: z.literal('coin') }),
714
- z.strictObject({ mode: z.literal('dice') }),
715
- z.strictObject({
716
- maximum: z.number().int(),
717
- minimum: z.number().int(),
718
- mode: z.literal('range'),
719
- }),
720
- z.strictObject({
721
- mode: z.literal('list'),
722
- options: z.array(z.string().max(160)).max(100),
723
- }),
724
- ])
725
- }
726
-
727
- function store<Shape extends z.ZodRawShape>(shape: Shape) {
728
- return z.object({
729
- configuration: z.record(z.string(), z.unknown()).nullable().default(null),
730
- configurationRevision: z.number().int().min(0).default(0),
731
- ...shape,
732
- })
733
- }
734
-
735
- /** A feature heading: never empty. */
736
- function title(): z.ZodString
737
- function title(fallback: string): z.ZodDefault<z.ZodString>
738
- function title(fallback?: string) {
739
- const schema = z.string().min(1).max(160)
740
- return fallback === undefined ? schema : schema.default(fallback)
741
- }
742
-
743
- function uniqueIds(items: ReadonlyArray<object>) {
744
- const ids = items.map(item => ('id' in item ? item.id : undefined))
745
- return new Set(ids).size === ids.length
746
- }
747
-
748
- function unit() {
749
- return z.enum(['m', 'km', 'mi', 'ft', 'kg', 'g', 'lb', 'c', 'f', 'k'])
750
- }
751
-
752
- function timeZone() {
753
- return z
754
- .string()
755
- .max(80)
756
- .refine(value => {
757
- try {
758
- new Intl.DateTimeFormat('en', { timeZone: value }).format(0)
759
- return true
760
- } catch {
761
- return false
762
- }
763
- }, 'Use a valid IANA time zone.')
764
- }
765
-
766
- /** Scheduled days of the week, by name. */
767
- function weekdays() {
768
- return z
769
- .array(z.enum(weekdayNames))
770
- .max(7)
771
- .default([...weekdayNames])
772
- }
773
-
774
- function webAddress() {
775
- return z
776
- .string()
777
- .max(2048)
778
- .refine(
779
- value => isURL(value, webAddressOptions),
780
- 'Use a valid HTTP or HTTPS address.'
781
- )
782
- }
783
-
784
- /** Catalog fields are whole-value replacements, not collaborative text insertions. */
785
- function replacement<Schema extends z.ZodType>(schema: Schema) {
786
- return z.object({ value: schema }).default(() => ({ value: schema.parse(undefined) }))
787
- }