@flickfyi/flkr 0.0.140 → 0.0.146

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 (494) hide show
  1. package/node_modules/@flickfyi/attestation/.turbo/turbo-build.log +7 -7
  2. package/node_modules/@flickfyi/biscuit/.turbo/turbo-build.log +7 -7
  3. package/node_modules/@flickfyi/core/.oxlintrc.json +2 -1
  4. package/node_modules/@flickfyi/core/.turbo/turbo-build.log +502 -95
  5. package/node_modules/@flickfyi/core/README.md +58 -4
  6. package/node_modules/@flickfyi/core/dist/index.cjs +1 -1
  7. package/node_modules/@flickfyi/core/dist/index.js +35 -24
  8. package/node_modules/@flickfyi/core/dist/kowalski/calculations.d.ts +17 -0
  9. package/node_modules/@flickfyi/core/dist/kowalski/calculator.d.ts +13 -0
  10. package/node_modules/@flickfyi/core/dist/kowalski/catalog.cjs +1 -0
  11. package/node_modules/@flickfyi/core/dist/kowalski/catalog.d.cts +962 -0
  12. package/node_modules/@flickfyi/core/dist/kowalski/catalog.d.ts +962 -0
  13. package/node_modules/@flickfyi/core/dist/kowalski/catalog.js +639 -0
  14. package/node_modules/@flickfyi/core/dist/kowalski/clocks.d.ts +4 -0
  15. package/node_modules/@flickfyi/core/dist/kowalski/date-time.d.ts +22 -0
  16. package/node_modules/@flickfyi/core/dist/kowalski/details.d.ts +7 -0
  17. package/node_modules/@flickfyi/core/dist/kowalski/everyday.d.ts +8 -0
  18. package/node_modules/@flickfyi/core/dist/kowalski/format.d.ts +4 -0
  19. package/node_modules/@flickfyi/core/dist/kowalski/frame.d.ts +161 -0
  20. package/node_modules/@flickfyi/core/dist/kowalski/index.cjs +21 -0
  21. package/node_modules/@flickfyi/core/dist/kowalski/index.d.cts +8 -0
  22. package/node_modules/@flickfyi/core/dist/kowalski/index.d.ts +8 -0
  23. package/node_modules/@flickfyi/core/dist/kowalski/index.js +7496 -0
  24. package/node_modules/@flickfyi/core/dist/kowalski/productivity.d.ts +5 -0
  25. package/node_modules/@flickfyi/core/dist/kowalski/recipe.d.ts +8 -0
  26. package/node_modules/@flickfyi/core/dist/kowalski/tools.d.ts +7 -0
  27. package/node_modules/@flickfyi/core/dist/kowalski/use-clock.d.ts +6 -0
  28. package/node_modules/@flickfyi/core/dist/kowalski/use-configured-feature.d.ts +19 -0
  29. package/node_modules/@flickfyi/core/dist/kowalski/use-feature-store.d.ts +15 -0
  30. package/node_modules/@flickfyi/core/dist/kowalski.css +506 -0
  31. package/node_modules/@flickfyi/core/dist/molecules/field/field.d.ts +8 -0
  32. package/node_modules/@flickfyi/core/dist/molecules/index.cjs +1 -1
  33. package/node_modules/@flickfyi/core/dist/molecules/index.d.cts +3 -0
  34. package/node_modules/@flickfyi/core/dist/molecules/index.d.ts +3 -0
  35. package/node_modules/@flickfyi/core/dist/molecules/index.js +88 -27
  36. package/node_modules/@flickfyi/core/dist/molecules/segmented/segmented.d.ts +10 -0
  37. package/node_modules/@flickfyi/core/dist/molecules/stepper/stepper.d.ts +10 -0
  38. package/node_modules/@flickfyi/core/dist/quantum/use-store.d.ts +7 -1
  39. package/node_modules/@flickfyi/core/dist/themes.css +2 -0
  40. package/node_modules/@flickfyi/core/examples/kowalski/bill-split/bill-split.stories.tsx +15 -0
  41. package/node_modules/@flickfyi/core/examples/kowalski/bill-split/bill-split.tsx +17 -0
  42. package/node_modules/@flickfyi/core/examples/kowalski/bookmark/bookmark.stories.tsx +15 -0
  43. package/node_modules/@flickfyi/core/examples/kowalski/bookmark/bookmark.tsx +23 -0
  44. package/node_modules/@flickfyi/core/examples/kowalski/budget/budget.stories.tsx +15 -0
  45. package/node_modules/@flickfyi/core/examples/kowalski/budget/budget.tsx +26 -0
  46. package/node_modules/@flickfyi/core/examples/kowalski/calculator/calculator.stories.tsx +15 -0
  47. package/node_modules/@flickfyi/core/examples/kowalski/calculator/calculator.tsx +24 -0
  48. package/node_modules/@flickfyi/core/examples/kowalski/checklist/checklist.stories.tsx +15 -0
  49. package/node_modules/@flickfyi/core/examples/kowalski/checklist/checklist.tsx +26 -0
  50. package/node_modules/@flickfyi/core/examples/kowalski/color-palette/color-palette.stories.tsx +15 -0
  51. package/node_modules/@flickfyi/core/examples/kowalski/color-palette/color-palette.tsx +22 -0
  52. package/node_modules/@flickfyi/core/examples/kowalski/contact/contact.stories.tsx +15 -0
  53. package/node_modules/@flickfyi/core/examples/kowalski/contact/contact.tsx +23 -0
  54. package/node_modules/@flickfyi/core/examples/kowalski/countdown/countdown.stories.tsx +15 -0
  55. package/node_modules/@flickfyi/core/examples/kowalski/countdown/countdown.tsx +23 -0
  56. package/node_modules/@flickfyi/core/examples/kowalski/event/event.stories.tsx +15 -0
  57. package/node_modules/@flickfyi/core/examples/kowalski/event/event.tsx +24 -0
  58. package/node_modules/@flickfyi/core/examples/kowalski/expense/expense.stories.tsx +15 -0
  59. package/node_modules/@flickfyi/core/examples/kowalski/expense/expense.tsx +23 -0
  60. package/node_modules/@flickfyi/core/examples/kowalski/goal/goal.stories.tsx +15 -0
  61. package/node_modules/@flickfyi/core/examples/kowalski/goal/goal.tsx +24 -0
  62. package/node_modules/@flickfyi/core/examples/kowalski/habit/habit.stories.tsx +15 -0
  63. package/node_modules/@flickfyi/core/examples/kowalski/habit/habit.tsx +23 -0
  64. package/node_modules/@flickfyi/core/examples/kowalski/ledger/ledger.stories.tsx +15 -0
  65. package/node_modules/@flickfyi/core/examples/kowalski/ledger/ledger.tsx +25 -0
  66. package/node_modules/@flickfyi/core/examples/kowalski/note/note.stories.tsx +15 -0
  67. package/node_modules/@flickfyi/core/examples/kowalski/note/note.tsx +22 -0
  68. package/node_modules/@flickfyi/core/examples/kowalski/poll/poll.stories.tsx +15 -0
  69. package/node_modules/@flickfyi/core/examples/kowalski/poll/poll.tsx +26 -0
  70. package/node_modules/@flickfyi/core/examples/kowalski/random-picker/random-picker.stories.tsx +15 -0
  71. package/node_modules/@flickfyi/core/examples/kowalski/random-picker/random-picker.tsx +23 -0
  72. package/node_modules/@flickfyi/core/examples/kowalski/rating/rating.stories.tsx +15 -0
  73. package/node_modules/@flickfyi/core/examples/kowalski/rating/rating.tsx +19 -0
  74. package/node_modules/@flickfyi/core/examples/kowalski/recipe/recipe.stories.tsx +15 -0
  75. package/node_modules/@flickfyi/core/examples/kowalski/recipe/recipe.tsx +120 -0
  76. package/node_modules/@flickfyi/core/examples/kowalski/reminder/reminder.stories.tsx +15 -0
  77. package/node_modules/@flickfyi/core/examples/kowalski/reminder/reminder.tsx +23 -0
  78. package/node_modules/@flickfyi/core/examples/kowalski/rotation/rotation.stories.tsx +15 -0
  79. package/node_modules/@flickfyi/core/examples/kowalski/rotation/rotation.tsx +27 -0
  80. package/node_modules/@flickfyi/core/examples/kowalski/scoreboard/scoreboard.stories.tsx +15 -0
  81. package/node_modules/@flickfyi/core/examples/kowalski/scoreboard/scoreboard.tsx +26 -0
  82. package/node_modules/@flickfyi/core/examples/kowalski/shopping-list/shopping-list.stories.tsx +15 -0
  83. package/node_modules/@flickfyi/core/examples/kowalski/shopping-list/shopping-list.tsx +27 -0
  84. package/node_modules/@flickfyi/core/examples/kowalski/task-board/task-board.stories.tsx +15 -0
  85. package/node_modules/@flickfyi/core/examples/kowalski/task-board/task-board.tsx +27 -0
  86. package/node_modules/@flickfyi/core/examples/kowalski/theme.ts +3 -0
  87. package/node_modules/@flickfyi/core/examples/kowalski/time-zone/time-zone.stories.tsx +15 -0
  88. package/node_modules/@flickfyi/core/examples/kowalski/time-zone/time-zone.tsx +22 -0
  89. package/node_modules/@flickfyi/core/examples/kowalski/timer/timer.stories.tsx +15 -0
  90. package/node_modules/@flickfyi/core/examples/kowalski/timer/timer.tsx +23 -0
  91. package/node_modules/@flickfyi/core/examples/kowalski/trip/trip.stories.tsx +15 -0
  92. package/node_modules/@flickfyi/core/examples/kowalski/trip/trip.tsx +26 -0
  93. package/node_modules/@flickfyi/core/examples/kowalski/unit-converter/unit-converter.stories.tsx +15 -0
  94. package/node_modules/@flickfyi/core/examples/kowalski/unit-converter/unit-converter.tsx +24 -0
  95. package/node_modules/@flickfyi/core/examples/parrott/calculator/calculator.stories.tsx +3 -1
  96. package/node_modules/@flickfyi/core/examples/parrott/checklist/checklist.stories.tsx +3 -1
  97. package/node_modules/@flickfyi/core/examples/parrott/countdown/countdown.stories.tsx +3 -1
  98. package/node_modules/@flickfyi/core/examples/parrott/counter/counter.stories.tsx +1 -0
  99. package/node_modules/@flickfyi/core/examples/parrott/fortune/fortune.stories.tsx +3 -1
  100. package/node_modules/@flickfyi/core/examples/parrott/grid/grid.stories.tsx +3 -1
  101. package/node_modules/@flickfyi/core/examples/parrott/kale-smoothie/kale-smoothie.stories.tsx +1 -0
  102. package/node_modules/@flickfyi/core/examples/parrott/list/list.stories.tsx +3 -1
  103. package/node_modules/@flickfyi/core/examples/parrott/log/log.stories.tsx +3 -1
  104. package/node_modules/@flickfyi/core/examples/parrott/timed-task/timed-task.stories.tsx +3 -1
  105. package/node_modules/@flickfyi/core/examples/parrott/timer/timer.stories.tsx +3 -1
  106. package/node_modules/@flickfyi/core/fixtures/native/host/project.yml +3 -0
  107. package/node_modules/@flickfyi/core/fixtures/native/src/catalog-features.tsx +88 -0
  108. package/node_modules/@flickfyi/core/package.json +35 -5
  109. package/node_modules/@flickfyi/core/package.tsgo.json +19 -1
  110. package/node_modules/@flickfyi/core/scripts/vite-globals.d.ts +2 -0
  111. package/node_modules/@flickfyi/core/src/generated-types.d.ts +1 -0
  112. package/node_modules/@flickfyi/core/src/kowalski/README.md +9 -0
  113. package/node_modules/@flickfyi/core/src/kowalski/calculations.ts +106 -0
  114. package/node_modules/@flickfyi/core/src/kowalski/calculator.ts +243 -0
  115. package/node_modules/@flickfyi/core/src/kowalski/catalog.ts +787 -0
  116. package/node_modules/@flickfyi/core/src/kowalski/clocks.tsx +464 -0
  117. package/node_modules/@flickfyi/core/src/kowalski/date-time.tsx +469 -0
  118. package/node_modules/@flickfyi/core/src/kowalski/details.tsx +1387 -0
  119. package/node_modules/@flickfyi/core/src/kowalski/everyday.tsx +652 -0
  120. package/node_modules/@flickfyi/core/src/kowalski/format.ts +48 -0
  121. package/node_modules/@flickfyi/core/src/kowalski/frame.tsx +351 -0
  122. package/node_modules/@flickfyi/core/src/kowalski/index.ts +23 -0
  123. package/node_modules/@flickfyi/core/src/kowalski/productivity.tsx +575 -0
  124. package/node_modules/@flickfyi/core/src/kowalski/recipe.tsx +555 -0
  125. package/node_modules/@flickfyi/core/src/kowalski/stories/composition.stories.tsx +47 -0
  126. package/node_modules/@flickfyi/core/src/kowalski/stories/composition.tsx +100 -0
  127. package/node_modules/@flickfyi/core/src/kowalski/tools.tsx +1213 -0
  128. package/node_modules/@flickfyi/core/src/kowalski/use-clock.ts +19 -0
  129. package/node_modules/@flickfyi/core/src/kowalski/use-configured-feature.ts +85 -0
  130. package/node_modules/@flickfyi/core/src/kowalski/use-feature-store.ts +119 -0
  131. package/node_modules/@flickfyi/core/src/molecules/field/field.tsx +34 -0
  132. package/node_modules/@flickfyi/core/src/molecules/index.ts +3 -0
  133. package/node_modules/@flickfyi/core/src/molecules/segmented/segmented.tsx +48 -0
  134. package/node_modules/@flickfyi/core/src/molecules/stepper/stepper.tsx +54 -0
  135. package/node_modules/@flickfyi/core/src/quantum/use-store.ts +41 -16
  136. package/node_modules/@flickfyi/core/tests/fly.test.ts +34 -7
  137. package/node_modules/@flickfyi/core/tests/kowalski-calculations.test.ts +60 -0
  138. package/node_modules/@flickfyi/core/tests/kowalski-calculator.test.ts +142 -0
  139. package/node_modules/@flickfyi/core/tests/kowalski-contracts.test.ts +223 -0
  140. package/node_modules/@flickfyi/core/tests/kowalski-date-time.test.tsx +462 -0
  141. package/node_modules/@flickfyi/core/tests/kowalski-features.test.tsx +2158 -0
  142. package/node_modules/@flickfyi/core/tests/kowalski-store.test.tsx +514 -0
  143. package/node_modules/@flickfyi/core/tests/preview-build.test.ts +1 -1
  144. package/node_modules/@flickfyi/core/tests/quantum-use-store.test.ts +53 -1
  145. package/node_modules/@flickfyi/core/tests/verify-tsgo-assets.test.ts +1 -1
  146. package/node_modules/@flickfyi/core/tsconfig.vite-dts.json +2 -1
  147. package/node_modules/@flickfyi/core/tsgo.bun.lock +111 -9
  148. package/node_modules/@flickfyi/core/tsgo.package.json +21 -3
  149. package/node_modules/@flickfyi/core/vite.config.ts +9 -5
  150. package/node_modules/@flickfyi/core/vitest.config.ts +1 -1
  151. package/node_modules/@flickfyi/http-message-sig/.turbo/turbo-build.log +7 -7
  152. package/node_modules/@flickfyi/identity/.turbo/turbo-build.log +8 -9
  153. package/node_modules/@flickfyi/lens/.turbo/turbo-build.log +7 -7
  154. package/node_modules/@flickfyi/photon/.turbo/turbo-build.log +9 -9
  155. package/node_modules/@flickfyi/photon/Sources/Photon/Components/Button.swift +29 -2
  156. package/node_modules/@flickfyi/photon/Sources/PhotonVersion/Resources/photon-version.json +1 -1
  157. package/node_modules/@flickfyi/photon/Tests/PhotonTests/Components/ButtonHostTests.swift +26 -0
  158. package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/catalog-features.styles.json +1 -0
  159. package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/catalog-native.styles.json +1 -1
  160. package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/catalog-scale.styles.json +1 -1
  161. package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/catalog-theme.styles.json +1 -1
  162. package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/catalog-typography.styles.json +1 -1
  163. package/node_modules/@flickfyi/photon/Tests/PhotonTests/Fixtures/StyleX/stylex-calculator.styles.json +1 -1
  164. package/node_modules/@flickfyi/photon/dist/globals.d.ts +5 -0
  165. package/node_modules/@flickfyi/photon/dist/version.cjs +1 -1
  166. package/node_modules/@flickfyi/photon/dist/version.js +1 -1
  167. package/node_modules/@flickfyi/photon/generated/react-swiftui.d.ts +1 -0
  168. package/node_modules/@flickfyi/photon/package.json +1 -1
  169. package/node_modules/@flickfyi/photon/src/globals.d.ts +5 -0
  170. package/node_modules/@flickfyi/rwsdk-extensions/.turbo/turbo-build.log +7 -7
  171. package/node_modules/@formatjs/fast-memoize/LICENSE.md +9 -0
  172. package/node_modules/@formatjs/fast-memoize/README.md +3 -0
  173. package/node_modules/@formatjs/fast-memoize/index.d.ts +35 -0
  174. package/node_modules/@formatjs/fast-memoize/index.js +69 -0
  175. package/node_modules/@formatjs/fast-memoize/index.js.map +1 -0
  176. package/node_modules/@formatjs/fast-memoize/package.json +25 -0
  177. package/node_modules/@formatjs/icu-messageformat-parser/LICENSE.md +9 -0
  178. package/node_modules/@formatjs/icu-messageformat-parser/README.md +38 -0
  179. package/node_modules/@formatjs/icu-messageformat-parser/index.d.ts +393 -0
  180. package/node_modules/@formatjs/icu-messageformat-parser/index.js +2187 -0
  181. package/node_modules/@formatjs/icu-messageformat-parser/index.js.map +1 -0
  182. package/node_modules/@formatjs/icu-messageformat-parser/manipulator.d.ts +175 -0
  183. package/node_modules/@formatjs/icu-messageformat-parser/manipulator.js +209 -0
  184. package/node_modules/@formatjs/icu-messageformat-parser/manipulator.js.map +1 -0
  185. package/node_modules/@formatjs/icu-messageformat-parser/no-parser.d.ts +183 -0
  186. package/node_modules/@formatjs/icu-messageformat-parser/no-parser.js +162 -0
  187. package/node_modules/@formatjs/icu-messageformat-parser/no-parser.js.map +1 -0
  188. package/node_modules/@formatjs/icu-messageformat-parser/package.json +21 -0
  189. package/node_modules/@formatjs/icu-messageformat-parser/printer.d.ts +154 -0
  190. package/node_modules/@formatjs/icu-messageformat-parser/printer.js +224 -0
  191. package/node_modules/@formatjs/icu-messageformat-parser/printer.js.map +1 -0
  192. package/node_modules/@formatjs/icu-skeleton-parser/LICENSE.md +9 -0
  193. package/node_modules/@formatjs/icu-skeleton-parser/README.md +1 -0
  194. package/node_modules/@formatjs/icu-skeleton-parser/index.d.ts +67 -0
  195. package/node_modules/@formatjs/icu-skeleton-parser/index.js +380 -0
  196. package/node_modules/@formatjs/icu-skeleton-parser/index.js.map +1 -0
  197. package/node_modules/@formatjs/icu-skeleton-parser/package.json +15 -0
  198. package/node_modules/@formatjs/intl/LICENSE.md +9 -0
  199. package/node_modules/@formatjs/intl/README.md +3 -0
  200. package/node_modules/@formatjs/intl/index.d.ts +499 -0
  201. package/node_modules/@formatjs/intl/index.js +595 -0
  202. package/node_modules/@formatjs/intl/index.js.map +1 -0
  203. package/node_modules/@formatjs/intl/package.json +37 -0
  204. package/node_modules/decimal.js/LICENCE.md +23 -0
  205. package/node_modules/decimal.js/README.md +246 -0
  206. package/node_modules/decimal.js/decimal.d.ts +301 -0
  207. package/node_modules/decimal.js/decimal.js +4951 -0
  208. package/node_modules/decimal.js/decimal.mjs +4914 -0
  209. package/node_modules/decimal.js/package.json +55 -0
  210. package/node_modules/format-quantity/LICENSE +21 -0
  211. package/node_modules/format-quantity/README.md +181 -0
  212. package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.development.d.ts +131 -0
  213. package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.development.js +214 -0
  214. package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.development.js.map +1 -0
  215. package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.production.d.ts +131 -0
  216. package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.production.js +2 -0
  217. package/node_modules/format-quantity/dist/cjs/format-quantity.cjs.production.js.map +1 -0
  218. package/node_modules/format-quantity/dist/cjs/index.d.ts +1 -0
  219. package/node_modules/format-quantity/dist/cjs/index.js +6 -0
  220. package/node_modules/format-quantity/dist/format-quantity.d.mts +131 -0
  221. package/node_modules/format-quantity/dist/format-quantity.legacy-esm.d.ts +131 -0
  222. package/node_modules/format-quantity/dist/format-quantity.legacy-esm.js +268 -0
  223. package/node_modules/format-quantity/dist/format-quantity.legacy-esm.js.map +1 -0
  224. package/node_modules/format-quantity/dist/format-quantity.mjs +208 -0
  225. package/node_modules/format-quantity/dist/format-quantity.mjs.map +1 -0
  226. package/node_modules/format-quantity/dist/format-quantity.production.d.mts +131 -0
  227. package/node_modules/format-quantity/dist/format-quantity.production.mjs +2 -0
  228. package/node_modules/format-quantity/dist/format-quantity.production.mjs.map +1 -0
  229. package/node_modules/format-quantity/dist/format-quantity.umd.min.js +3 -0
  230. package/node_modules/format-quantity/dist/format-quantity.umd.min.js.map +1 -0
  231. package/node_modules/format-quantity/package.json +81 -0
  232. package/node_modules/intl-messageformat/LICENSE.md +33 -0
  233. package/node_modules/intl-messageformat/README.md +3 -0
  234. package/node_modules/intl-messageformat/index.d.ts +177 -0
  235. package/node_modules/intl-messageformat/index.js +327 -0
  236. package/node_modules/intl-messageformat/index.js.map +1 -0
  237. package/node_modules/intl-messageformat/intl-messageformat.iife.js +2819 -0
  238. package/node_modules/intl-messageformat/package.json +40 -0
  239. package/node_modules/numeric-quantity/LICENSE +21 -0
  240. package/node_modules/numeric-quantity/README.md +306 -0
  241. package/node_modules/numeric-quantity/dist/cjs/index.d.ts +1 -0
  242. package/node_modules/numeric-quantity/dist/cjs/index.js +6 -0
  243. package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.development.d.ts +293 -0
  244. package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.development.js +579 -0
  245. package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.development.js.map +1 -0
  246. package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.production.d.ts +293 -0
  247. package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.production.js +2 -0
  248. package/node_modules/numeric-quantity/dist/cjs/numeric-quantity.cjs.production.js.map +1 -0
  249. package/node_modules/numeric-quantity/dist/numeric-quantity.d.mts +293 -0
  250. package/node_modules/numeric-quantity/dist/numeric-quantity.iife.umd.min.js +2 -0
  251. package/node_modules/numeric-quantity/dist/numeric-quantity.iife.umd.min.js.map +1 -0
  252. package/node_modules/numeric-quantity/dist/numeric-quantity.legacy-esm.d.ts +293 -0
  253. package/node_modules/numeric-quantity/dist/numeric-quantity.legacy-esm.js +622 -0
  254. package/node_modules/numeric-quantity/dist/numeric-quantity.legacy-esm.js.map +1 -0
  255. package/node_modules/numeric-quantity/dist/numeric-quantity.mjs +564 -0
  256. package/node_modules/numeric-quantity/dist/numeric-quantity.mjs.map +1 -0
  257. package/node_modules/numeric-quantity/dist/numeric-quantity.production.d.mts +293 -0
  258. package/node_modules/numeric-quantity/dist/numeric-quantity.production.mjs +2 -0
  259. package/node_modules/numeric-quantity/dist/numeric-quantity.production.mjs.map +1 -0
  260. package/node_modules/numeric-quantity/package.json +72 -0
  261. package/node_modules/validator/LICENSE +20 -0
  262. package/node_modules/validator/README.md +269 -0
  263. package/node_modules/validator/es/index.js +218 -0
  264. package/node_modules/validator/es/lib/alpha.js +151 -0
  265. package/node_modules/validator/es/lib/blacklist.js +5 -0
  266. package/node_modules/validator/es/lib/contains.js +15 -0
  267. package/node_modules/validator/es/lib/equals.js +5 -0
  268. package/node_modules/validator/es/lib/escape.js +5 -0
  269. package/node_modules/validator/es/lib/isAbaRouting.js +15 -0
  270. package/node_modules/validator/es/lib/isAfter.js +10 -0
  271. package/node_modules/validator/es/lib/isAlpha.js +23 -0
  272. package/node_modules/validator/es/lib/isAlphanumeric.js +23 -0
  273. package/node_modules/validator/es/lib/isAscii.js +10 -0
  274. package/node_modules/validator/es/lib/isBIC.js +16 -0
  275. package/node_modules/validator/es/lib/isBase32.js +15 -0
  276. package/node_modules/validator/es/lib/isBase58.js +8 -0
  277. package/node_modules/validator/es/lib/isBase64.js +23 -0
  278. package/node_modules/validator/es/lib/isBefore.js +10 -0
  279. package/node_modules/validator/es/lib/isBoolean.js +15 -0
  280. package/node_modules/validator/es/lib/isBtcAddress.js +7 -0
  281. package/node_modules/validator/es/lib/isByteLength.js +19 -0
  282. package/node_modules/validator/es/lib/isCreditCard.js +43 -0
  283. package/node_modules/validator/es/lib/isCurrency.js +74 -0
  284. package/node_modules/validator/es/lib/isDataURI.js +31 -0
  285. package/node_modules/validator/es/lib/isDate.js +93 -0
  286. package/node_modules/validator/es/lib/isDecimal.js +22 -0
  287. package/node_modules/validator/es/lib/isDivisibleBy.js +6 -0
  288. package/node_modules/validator/es/lib/isEAN.js +70 -0
  289. package/node_modules/validator/es/lib/isEmail.js +165 -0
  290. package/node_modules/validator/es/lib/isEmpty.js +10 -0
  291. package/node_modules/validator/es/lib/isEthereumAddress.js +6 -0
  292. package/node_modules/validator/es/lib/isFQDN.js +67 -0
  293. package/node_modules/validator/es/lib/isFloat.js +14 -0
  294. package/node_modules/validator/es/lib/isFullWidth.js +6 -0
  295. package/node_modules/validator/es/lib/isHSL.js +13 -0
  296. package/node_modules/validator/es/lib/isHalfWidth.js +6 -0
  297. package/node_modules/validator/es/lib/isHash.js +21 -0
  298. package/node_modules/validator/es/lib/isHexColor.js +13 -0
  299. package/node_modules/validator/es/lib/isHexadecimal.js +6 -0
  300. package/node_modules/validator/es/lib/isIBAN.js +171 -0
  301. package/node_modules/validator/es/lib/isIMEI.js +40 -0
  302. package/node_modules/validator/es/lib/isIP.js +58 -0
  303. package/node_modules/validator/es/lib/isIPRange.js +41 -0
  304. package/node_modules/validator/es/lib/isISBN.js +47 -0
  305. package/node_modules/validator/es/lib/isISIN.js +55 -0
  306. package/node_modules/validator/es/lib/isISO15924.js +9 -0
  307. package/node_modules/validator/es/lib/isISO31661Alpha2.js +21 -0
  308. package/node_modules/validator/es/lib/isISO31661Alpha3.js +20 -0
  309. package/node_modules/validator/es/lib/isISO31661Numeric.js +8 -0
  310. package/node_modules/validator/es/lib/isISO4217.js +9 -0
  311. package/node_modules/validator/es/lib/isISO6346.js +28 -0
  312. package/node_modules/validator/es/lib/isISO6391.js +6 -0
  313. package/node_modules/validator/es/lib/isISO8601.js +42 -0
  314. package/node_modules/validator/es/lib/isISRC.js +8 -0
  315. package/node_modules/validator/es/lib/isISSN.js +19 -0
  316. package/node_modules/validator/es/lib/isIdentityCard.js +407 -0
  317. package/node_modules/validator/es/lib/isIn.js +23 -0
  318. package/node_modules/validator/es/lib/isInt.js +19 -0
  319. package/node_modules/validator/es/lib/isJSON.js +26 -0
  320. package/node_modules/validator/es/lib/isJWT.js +15 -0
  321. package/node_modules/validator/es/lib/isLatLong.js +21 -0
  322. package/node_modules/validator/es/lib/isLength.js +27 -0
  323. package/node_modules/validator/es/lib/isLicensePlate.js +58 -0
  324. package/node_modules/validator/es/lib/isLocale.js +107 -0
  325. package/node_modules/validator/es/lib/isLowercase.js +5 -0
  326. package/node_modules/validator/es/lib/isLuhnNumber.js +25 -0
  327. package/node_modules/validator/es/lib/isMACAddress.js +36 -0
  328. package/node_modules/validator/es/lib/isMD5.js +6 -0
  329. package/node_modules/validator/es/lib/isMagnetURI.js +9 -0
  330. package/node_modules/validator/es/lib/isMailtoURI.js +75 -0
  331. package/node_modules/validator/es/lib/isMimeType.js +40 -0
  332. package/node_modules/validator/es/lib/isMobilePhone.js +212 -0
  333. package/node_modules/validator/es/lib/isMongoId.js +6 -0
  334. package/node_modules/validator/es/lib/isMultibyte.js +10 -0
  335. package/node_modules/validator/es/lib/isNumeric.js +10 -0
  336. package/node_modules/validator/es/lib/isOctal.js +6 -0
  337. package/node_modules/validator/es/lib/isPassportNumber.js +145 -0
  338. package/node_modules/validator/es/lib/isPort.js +8 -0
  339. package/node_modules/validator/es/lib/isPostalCode.js +100 -0
  340. package/node_modules/validator/es/lib/isRFC3339.js +21 -0
  341. package/node_modules/validator/es/lib/isRgbColor.js +34 -0
  342. package/node_modules/validator/es/lib/isSemVer.js +14 -0
  343. package/node_modules/validator/es/lib/isSlug.js +6 -0
  344. package/node_modules/validator/es/lib/isStrongPassword.js +90 -0
  345. package/node_modules/validator/es/lib/isSurrogatePair.js +6 -0
  346. package/node_modules/validator/es/lib/isTaxID.js +1407 -0
  347. package/node_modules/validator/es/lib/isTime.js +22 -0
  348. package/node_modules/validator/es/lib/isULID.js +5 -0
  349. package/node_modules/validator/es/lib/isURL.js +241 -0
  350. package/node_modules/validator/es/lib/isUUID.js +23 -0
  351. package/node_modules/validator/es/lib/isUppercase.js +5 -0
  352. package/node_modules/validator/es/lib/isVAT.js +264 -0
  353. package/node_modules/validator/es/lib/isVariableWidth.js +7 -0
  354. package/node_modules/validator/es/lib/isWhitelisted.js +10 -0
  355. package/node_modules/validator/es/lib/ltrim.js +7 -0
  356. package/node_modules/validator/es/lib/matches.js +8 -0
  357. package/node_modules/validator/es/lib/normalizeEmail.js +131 -0
  358. package/node_modules/validator/es/lib/rtrim.js +15 -0
  359. package/node_modules/validator/es/lib/stripLow.js +7 -0
  360. package/node_modules/validator/es/lib/toBoolean.js +8 -0
  361. package/node_modules/validator/es/lib/toDate.js +6 -0
  362. package/node_modules/validator/es/lib/toFloat.js +5 -0
  363. package/node_modules/validator/es/lib/toInt.js +5 -0
  364. package/node_modules/validator/es/lib/trim.js +5 -0
  365. package/node_modules/validator/es/lib/unescape.js +8 -0
  366. package/node_modules/validator/es/lib/util/algorithms.js +79 -0
  367. package/node_modules/validator/es/lib/util/assertString.js +4 -0
  368. package/node_modules/validator/es/lib/util/checkHost.js +12 -0
  369. package/node_modules/validator/es/lib/util/includesArray.js +6 -0
  370. package/node_modules/validator/es/lib/util/includesString.js +4 -0
  371. package/node_modules/validator/es/lib/util/merge.js +14 -0
  372. package/node_modules/validator/es/lib/util/multilineRegex.js +12 -0
  373. package/node_modules/validator/es/lib/util/nullUndefinedCheck.js +3 -0
  374. package/node_modules/validator/es/lib/util/toString.js +13 -0
  375. package/node_modules/validator/es/lib/util/typeOf.js +10 -0
  376. package/node_modules/validator/es/lib/whitelist.js +5 -0
  377. package/node_modules/validator/index.js +229 -0
  378. package/node_modules/validator/lib/alpha.js +157 -0
  379. package/node_modules/validator/lib/blacklist.js +14 -0
  380. package/node_modules/validator/lib/contains.js +24 -0
  381. package/node_modules/validator/lib/equals.js +14 -0
  382. package/node_modules/validator/lib/escape.js +14 -0
  383. package/node_modules/validator/lib/isAbaRouting.js +23 -0
  384. package/node_modules/validator/lib/isAfter.js +19 -0
  385. package/node_modules/validator/lib/isAlpha.js +31 -0
  386. package/node_modules/validator/lib/isAlphanumeric.js +31 -0
  387. package/node_modules/validator/lib/isAscii.js +18 -0
  388. package/node_modules/validator/lib/isBIC.js +24 -0
  389. package/node_modules/validator/lib/isBase32.js +24 -0
  390. package/node_modules/validator/lib/isBase58.js +16 -0
  391. package/node_modules/validator/lib/isBase64.js +32 -0
  392. package/node_modules/validator/lib/isBefore.js +19 -0
  393. package/node_modules/validator/lib/isBoolean.js +24 -0
  394. package/node_modules/validator/lib/isBtcAddress.js +16 -0
  395. package/node_modules/validator/lib/isByteLength.js +27 -0
  396. package/node_modules/validator/lib/isCreditCard.js +52 -0
  397. package/node_modules/validator/lib/isCurrency.js +83 -0
  398. package/node_modules/validator/lib/isDataURI.js +40 -0
  399. package/node_modules/validator/lib/isDate.js +102 -0
  400. package/node_modules/validator/lib/isDecimal.js +31 -0
  401. package/node_modules/validator/lib/isDivisibleBy.js +15 -0
  402. package/node_modules/validator/lib/isEAN.js +78 -0
  403. package/node_modules/validator/lib/isEmail.js +174 -0
  404. package/node_modules/validator/lib/isEmpty.js +19 -0
  405. package/node_modules/validator/lib/isEthereumAddress.js +15 -0
  406. package/node_modules/validator/lib/isFQDN.js +76 -0
  407. package/node_modules/validator/lib/isFloat.js +22 -0
  408. package/node_modules/validator/lib/isFullWidth.js +14 -0
  409. package/node_modules/validator/lib/isHSL.js +22 -0
  410. package/node_modules/validator/lib/isHalfWidth.js +14 -0
  411. package/node_modules/validator/lib/isHash.js +30 -0
  412. package/node_modules/validator/lib/isHexColor.js +22 -0
  413. package/node_modules/validator/lib/isHexadecimal.js +15 -0
  414. package/node_modules/validator/lib/isIBAN.js +178 -0
  415. package/node_modules/validator/lib/isIMEI.js +49 -0
  416. package/node_modules/validator/lib/isIP.js +67 -0
  417. package/node_modules/validator/lib/isIPRange.js +50 -0
  418. package/node_modules/validator/lib/isISBN.js +56 -0
  419. package/node_modules/validator/lib/isISIN.js +64 -0
  420. package/node_modules/validator/lib/isISO15924.js +16 -0
  421. package/node_modules/validator/lib/isISO31661Alpha2.js +28 -0
  422. package/node_modules/validator/lib/isISO31661Alpha3.js +28 -0
  423. package/node_modules/validator/lib/isISO31661Numeric.js +16 -0
  424. package/node_modules/validator/lib/isISO4217.js +16 -0
  425. package/node_modules/validator/lib/isISO6346.js +35 -0
  426. package/node_modules/validator/lib/isISO6391.js +15 -0
  427. package/node_modules/validator/lib/isISO8601.js +50 -0
  428. package/node_modules/validator/lib/isISRC.js +16 -0
  429. package/node_modules/validator/lib/isISSN.js +28 -0
  430. package/node_modules/validator/lib/isIdentityCard.js +416 -0
  431. package/node_modules/validator/lib/isIn.js +32 -0
  432. package/node_modules/validator/lib/isInt.js +28 -0
  433. package/node_modules/validator/lib/isJSON.js +35 -0
  434. package/node_modules/validator/lib/isJWT.js +24 -0
  435. package/node_modules/validator/lib/isLatLong.js +30 -0
  436. package/node_modules/validator/lib/isLength.js +35 -0
  437. package/node_modules/validator/lib/isLicensePlate.js +67 -0
  438. package/node_modules/validator/lib/isLocale.js +115 -0
  439. package/node_modules/validator/lib/isLowercase.js +14 -0
  440. package/node_modules/validator/lib/isLuhnNumber.js +34 -0
  441. package/node_modules/validator/lib/isMACAddress.js +45 -0
  442. package/node_modules/validator/lib/isMD5.js +15 -0
  443. package/node_modules/validator/lib/isMagnetURI.js +18 -0
  444. package/node_modules/validator/lib/isMailtoURI.js +84 -0
  445. package/node_modules/validator/lib/isMimeType.js +48 -0
  446. package/node_modules/validator/lib/isMobilePhone.js +219 -0
  447. package/node_modules/validator/lib/isMongoId.js +15 -0
  448. package/node_modules/validator/lib/isMultibyte.js +18 -0
  449. package/node_modules/validator/lib/isNumeric.js +19 -0
  450. package/node_modules/validator/lib/isOctal.js +15 -0
  451. package/node_modules/validator/lib/isPassportNumber.js +152 -0
  452. package/node_modules/validator/lib/isPort.js +17 -0
  453. package/node_modules/validator/lib/isPostalCode.js +107 -0
  454. package/node_modules/validator/lib/isRFC3339.js +29 -0
  455. package/node_modules/validator/lib/isRgbColor.js +42 -0
  456. package/node_modules/validator/lib/isSemVer.js +22 -0
  457. package/node_modules/validator/lib/isSlug.js +15 -0
  458. package/node_modules/validator/lib/isStrongPassword.js +99 -0
  459. package/node_modules/validator/lib/isSurrogatePair.js +15 -0
  460. package/node_modules/validator/lib/isTaxID.js +1417 -0
  461. package/node_modules/validator/lib/isTime.js +31 -0
  462. package/node_modules/validator/lib/isULID.js +14 -0
  463. package/node_modules/validator/lib/isURL.js +249 -0
  464. package/node_modules/validator/lib/isUUID.js +32 -0
  465. package/node_modules/validator/lib/isUppercase.js +14 -0
  466. package/node_modules/validator/lib/isVAT.js +274 -0
  467. package/node_modules/validator/lib/isVariableWidth.js +16 -0
  468. package/node_modules/validator/lib/isWhitelisted.js +19 -0
  469. package/node_modules/validator/lib/ltrim.js +16 -0
  470. package/node_modules/validator/lib/matches.js +17 -0
  471. package/node_modules/validator/lib/normalizeEmail.js +140 -0
  472. package/node_modules/validator/lib/rtrim.js +24 -0
  473. package/node_modules/validator/lib/stripLow.js +16 -0
  474. package/node_modules/validator/lib/toBoolean.js +17 -0
  475. package/node_modules/validator/lib/toDate.js +15 -0
  476. package/node_modules/validator/lib/toFloat.js +14 -0
  477. package/node_modules/validator/lib/toInt.js +14 -0
  478. package/node_modules/validator/lib/trim.js +14 -0
  479. package/node_modules/validator/lib/unescape.js +17 -0
  480. package/node_modules/validator/lib/util/algorithms.js +88 -0
  481. package/node_modules/validator/lib/util/assertString.js +12 -0
  482. package/node_modules/validator/lib/util/checkHost.js +20 -0
  483. package/node_modules/validator/lib/util/includesArray.js +14 -0
  484. package/node_modules/validator/lib/util/includesString.js +12 -0
  485. package/node_modules/validator/lib/util/merge.js +22 -0
  486. package/node_modules/validator/lib/util/multilineRegex.js +20 -0
  487. package/node_modules/validator/lib/util/nullUndefinedCheck.js +11 -0
  488. package/node_modules/validator/lib/util/toString.js +21 -0
  489. package/node_modules/validator/lib/util/typeOf.js +18 -0
  490. package/node_modules/validator/lib/whitelist.js +14 -0
  491. package/node_modules/validator/package.json +76 -0
  492. package/node_modules/validator/validator.js +5808 -0
  493. package/node_modules/validator/validator.min.js +23 -0
  494. package/package.json +3 -3
@@ -0,0 +1,575 @@
1
+ import { Flex, Icon, Text } from '@flickfyi/core'
2
+ import { Button } from '@flickfyi/core/atoms'
3
+ import { Field } from '@flickfyi/core/molecules'
4
+ import * as stylex from '@stylexjs/stylex'
5
+ import { Decimal } from 'decimal.js'
6
+ import { isEqual } from 'lodash'
7
+ import { Info } from 'luxon'
8
+ import { useMemo, useState } from 'react'
9
+
10
+ import { radius, size, space, text } from '~/themes/scale.stylex'
11
+ import { appearance, button, roles } from '~/themes/shared'
12
+ import { colors, font, shape } from '~/themes/tokens.stylex'
13
+
14
+ import { localDate } from './calculations'
15
+ import {
16
+ kowalskiCatalog,
17
+ type KowalskiInput,
18
+ pollVoterSchema,
19
+ type Weekday,
20
+ weekdayNames,
21
+ } from './catalog'
22
+ import { format } from './format'
23
+ import {
24
+ FeatureAction,
25
+ FeatureChoice,
26
+ FeatureFrame,
27
+ FeatureProgress,
28
+ FeatureWell,
29
+ layout,
30
+ } from './frame'
31
+ import { useClock } from './use-clock'
32
+ import { useConfiguredFeature } from './use-configured-feature'
33
+ import { useFeatureStore } from './use-feature-store'
34
+
35
+ export function Checklist(input: KowalskiInput<'checklist'>) {
36
+ const props = kowalskiCatalog.checklist.props.parse(input)
37
+ const items = props.items
38
+ const schema = kowalskiCatalog.checklist.storeSchema
39
+ const store = useConfiguredFeature({
40
+ name: props.id ?? 'KowalskiChecklist',
41
+ revision: props.revision,
42
+ schema,
43
+ scope: props.scope,
44
+ seed: schema.parse({}),
45
+ })
46
+ const completed = (id: string) => store.value[`completed_${id}`] === true
47
+ const count = items.filter(item => completed(item.id)).length
48
+ const loading = !store.ready && !store.error
49
+ const remaining = items.length - count
50
+ return (
51
+ <FeatureFrame
52
+ onRetry={store.retry}
53
+ notice={store.error}
54
+ component="checklist"
55
+ title={props.title}
56
+ trailing={
57
+ <Flex {...stylex.props(checklistStyles.status)}>
58
+ {!loading && remaining === 0 && (
59
+ <Icon name="checkmark.circle.fill" {...stylex.props(appearance.accent)} />
60
+ )}
61
+ <Text {...stylex.props(roles.muted)}>
62
+ {loading
63
+ ? 'Loading checklist…'
64
+ : `${format.formatNumber(count)} of ${format.formatNumber(items.length)} complete`}
65
+ </Text>
66
+ </Flex>
67
+ }
68
+ >
69
+ <Flex {...stylex.props(layout.list)}>
70
+ {/* Completed items sink below open ones; each group keeps its authored order. */}
71
+ {items
72
+ .toSorted((a, b) => Number(completed(a.id)) - Number(completed(b.id)))
73
+ .map(item => (
74
+ <FeatureChoice
75
+ key={item.id}
76
+ component="checklist"
77
+ label={item.label}
78
+ ready={store.ready}
79
+ selected={completed(item.id)}
80
+ onClick={() => {
81
+ store.set(current => ({
82
+ [`completed_${item.id}`]: current[`completed_${item.id}`] !== true,
83
+ }))
84
+ }}
85
+ />
86
+ ))}
87
+ </Flex>
88
+ {store.saving && <Text {...stylex.props(roles.muted)}>Saving changes…</Text>}
89
+ </FeatureFrame>
90
+ )
91
+ }
92
+
93
+ export function Goal(input: KowalskiInput<'goal'>) {
94
+ const props = kowalskiCatalog.goal.props.parse(input)
95
+ const schema = kowalskiCatalog.goal.storeSchema
96
+ const store = useConfiguredFeature({
97
+ name: props.id ?? 'KowalskiGoal',
98
+ revision: props.revision,
99
+ schema,
100
+ scope: props.scope,
101
+ seed: schema.parse({ progress: props.progress }),
102
+ })
103
+ const progress = store.value.progress
104
+ const loading = !store.ready && !store.error
105
+ const reached = !loading && progress >= props.target
106
+ const number = useMemo(
107
+ () =>
108
+ format.formatters.getNumberFormat(format.locale, { maximumSignificantDigits: 17 }),
109
+ []
110
+ )
111
+ const distance = new Decimal(props.target).minus(progress).abs().toNumber()
112
+ const progressLabel = loading ? '—' : number.format(progress)
113
+ const targetLabel = number.format(props.target)
114
+ const distanceLabel = number.format(distance)
115
+ const stepLabel = number.format(props.step)
116
+ const nextProgress = new Decimal(progress).plus(props.step).toNumber()
117
+ const previousProgress = Decimal.max(
118
+ 0,
119
+ new Decimal(progress).minus(props.step)
120
+ ).toNumber()
121
+ const unit = props.unit ? ` ${props.unit}` : ''
122
+ const change = (direction: -1 | 1) =>
123
+ store.set(current => {
124
+ const next = Decimal.max(
125
+ 0,
126
+ new Decimal(current.progress).plus(props.step * direction)
127
+ ).toNumber()
128
+ return { progress: Number.isFinite(next) ? next : current.progress }
129
+ })
130
+ return (
131
+ <FeatureFrame
132
+ onRetry={store.retry}
133
+ notice={store.error}
134
+ component="goal"
135
+ title={props.title}
136
+ >
137
+ <FeatureWell>
138
+ <Flex {...stylex.props(goalStyles.metric)}>
139
+ <Text
140
+ animated="numeric"
141
+ {...stylex.props(roles.display, goalStyles.value(progressLabel.length))}
142
+ >
143
+ {progressLabel}
144
+ </Text>
145
+ <Text {...stylex.props(roles.muted)}>{`of ${targetLabel}${unit}`}</Text>
146
+ </Flex>
147
+ <FeatureProgress component="goal" value={loading ? 0 : progress / props.target} />
148
+ {(loading || reached) && (
149
+ <Flex {...stylex.props(goalStyles.status)}>
150
+ {reached && (
151
+ <Icon name="checkmark.circle.fill" {...stylex.props(appearance.accent)} />
152
+ )}
153
+ <Text {...stylex.props(roles.muted, reached && appearance.accent)}>
154
+ {loading
155
+ ? 'Loading saved progress…'
156
+ : progress > props.target
157
+ ? `Goal reached, ${distanceLabel}${unit} beyond your target`
158
+ : 'Goal reached'}
159
+ </Text>
160
+ </Flex>
161
+ )}
162
+ </FeatureWell>
163
+ <Flex {...stylex.props(goalStyles.controls)}>
164
+ <Flex {...stylex.props(layout.actions)}>
165
+ <FeatureAction
166
+ component="goal"
167
+ disabled={!store.ready || previousProgress === progress}
168
+ onClick={() => change(-1)}
169
+ >{`−${stepLabel}`}</FeatureAction>
170
+ <FeatureAction
171
+ component="goal"
172
+ variant="primary"
173
+ disabled={
174
+ !store.ready || !Number.isFinite(nextProgress) || nextProgress === progress
175
+ }
176
+ onClick={() => change(1)}
177
+ >{`+${stepLabel}`}</FeatureAction>
178
+ </Flex>
179
+ {store.saving && <Text {...stylex.props(roles.muted)}>Saving progress…</Text>}
180
+ {store.ready && nextProgress === progress && previousProgress === progress && (
181
+ <Text {...stylex.props(roles.muted)}>
182
+ This increment is too small to change this total.
183
+ </Text>
184
+ )}
185
+ </Flex>
186
+ </FeatureFrame>
187
+ )
188
+ }
189
+
190
+ export function Habit(input: KowalskiInput<'habit'>) {
191
+ const props = kowalskiCatalog.habit.props.parse(input)
192
+ const [editingSchedule, setEditingSchedule] = useState(false)
193
+ const schema = kowalskiCatalog.habit.storeSchema
194
+ const store = useConfiguredFeature({
195
+ name: props.id ?? 'KowalskiHabit',
196
+ revision: props.revision,
197
+ schema,
198
+ scope: props.scope,
199
+ seed: schema.parse({ weekdays: props.weekdays }),
200
+ })
201
+ const now = useClock()
202
+ const today = localDate(now, props.timeZone)
203
+ const loading = !store.ready && !store.error
204
+ const dayOf = (date: string) => weekdayNames[new Date(`${date}T00:00:00Z`).getUTCDay()]
205
+ // Luxon lists weekdays Monday first; weekdayNames is Sunday first.
206
+ const shortName = (day: Weekday) =>
207
+ Info.weekdays('short', { locale: format.locale })[(weekdayNames.indexOf(day) + 6) % 7]
208
+ const scheduled = store.value.weekdays.includes(dayOf(today))
209
+ const done = store.value[`completed_${today}`] === true
210
+ const mondayFirst = [...weekdayNames.slice(1), weekdayNames[0]]
211
+ const selected = mondayFirst.filter(day => store.value.weekdays.includes(day))
212
+ const schedule =
213
+ selected.length === 7
214
+ ? 'Every day'
215
+ : selected.length === 0
216
+ ? 'No scheduled days'
217
+ : isEqual(selected, mondayFirst.slice(0, 5))
218
+ ? 'Monday to Friday'
219
+ : isEqual(selected, mondayFirst.slice(5))
220
+ ? 'Saturday & Sunday'
221
+ : format.formatList(selected.map(shortName), { type: 'unit' })
222
+ const days = Array.from({ length: 7 }, (_, index) => {
223
+ const date = new Date(`${today}T00:00:00Z`)
224
+ date.setUTCDate(date.getUTCDate() - 6 + index)
225
+ const key = date.toISOString().slice(0, 10)
226
+ return {
227
+ complete: store.value[`completed_${key}`] === true,
228
+ date: key,
229
+ label: shortName(dayOf(key)),
230
+ number: date.getUTCDate(),
231
+ scheduled: store.value.weekdays.includes(dayOf(key)),
232
+ }
233
+ })
234
+ return (
235
+ <FeatureFrame
236
+ onRetry={store.retry}
237
+ notice={store.error}
238
+ component="habit"
239
+ title={props.title}
240
+ >
241
+ <Field label="Schedule">
242
+ <Flex {...stylex.props(habitStyles.row)}>
243
+ <Text {...stylex.props(roles.text, layout.grow)}>
244
+ {loading ? 'Loading saved schedule…' : schedule}
245
+ </Text>
246
+ <Button
247
+ disabled={!store.ready}
248
+ onClick={() => setEditingSchedule(current => !current)}
249
+ style={[button.quiet, layout.trailingAction]}
250
+ >
251
+ <Text>{editingSchedule ? 'Done editing' : 'Edit schedule'}</Text>
252
+ </Button>
253
+ </Flex>
254
+ {editingSchedule && (
255
+ <>
256
+ <Flex {...stylex.props(habitStyles.weekdays)}>
257
+ {mondayFirst.map(day => (
258
+ <Button
259
+ key={day}
260
+ selected={store.value.weekdays.includes(day)}
261
+ disabled={!store.ready}
262
+ onClick={() => {
263
+ store.set(current => ({
264
+ weekdays: current.weekdays.includes(day)
265
+ ? current.weekdays.filter(value => value !== day)
266
+ : [...current.weekdays, day],
267
+ }))
268
+ }}
269
+ style={[button.secondary, habitStyles.weekday]}
270
+ >
271
+ <Text>{shortName(day)}</Text>
272
+ </Button>
273
+ ))}
274
+ </Flex>
275
+ <Text {...stylex.props(roles.muted)}>
276
+ Changes save as you tap. Completed days stay saved when the schedule
277
+ changes.
278
+ </Text>
279
+ </>
280
+ )}
281
+ </Field>
282
+ <Field label="Last seven days">
283
+ {loading ? (
284
+ <Text {...stylex.props(roles.muted)}>Loading saved history…</Text>
285
+ ) : (
286
+ <Flex {...stylex.props(habitStyles.history)}>
287
+ {days.map(day => (
288
+ <Flex key={day.date} {...stylex.props(habitStyles.day)}>
289
+ <Text
290
+ {...stylex.props(roles.muted, day.date === today && appearance.accent)}
291
+ >
292
+ {day.date === today ? 'Today' : day.label}
293
+ </Text>
294
+ <Flex
295
+ {...stylex.props(
296
+ appearance.surface,
297
+ habitStyles.date,
298
+ day.date === today && appearance.selected,
299
+ day.complete && habitStyles.completedDate,
300
+ !day.scheduled && !day.complete && habitStyles.offDay
301
+ )}
302
+ >
303
+ <Text>{day.number}</Text>
304
+ </Flex>
305
+ </Flex>
306
+ ))}
307
+ </Flex>
308
+ )}
309
+ </Field>
310
+ <FeatureWell>
311
+ <Flex {...stylex.props(habitStyles.row)}>
312
+ <Text {...stylex.props(roles.h1)}>
313
+ {loading ? 'Loading…' : done ? 'Complete' : scheduled ? 'Not yet' : 'Off day'}
314
+ </Text>
315
+ <Text {...stylex.props(roles.muted)}>
316
+ {format.formatters
317
+ .getDateTimeFormat(format.locale, {
318
+ day: 'numeric',
319
+ month: 'short',
320
+ timeZone: 'UTC',
321
+ weekday: 'short',
322
+ })
323
+ .format(new Date(`${today}T00:00:00Z`))}
324
+ </Text>
325
+ </Flex>
326
+ <Text {...stylex.props(roles.muted)}>
327
+ {loading
328
+ ? 'Loading saved completions…'
329
+ : scheduled
330
+ ? 'Scheduled today'
331
+ : done
332
+ ? 'Completed on an off day'
333
+ : 'No completion needed today'}
334
+ </Text>
335
+ </FeatureWell>
336
+ {store.saving && <Text {...stylex.props(roles.muted)}>Saving changes…</Text>}
337
+ <FeatureAction
338
+ component="habit"
339
+ variant={done || !scheduled ? 'secondary' : 'primary'}
340
+ icon={done ? 'arrow.uturn.backward' : 'checkmark'}
341
+ size="lg"
342
+ disabled={!store.ready}
343
+ onClick={() => {
344
+ store.set(current => ({
345
+ [`completed_${today}`]: current[`completed_${today}`] !== true,
346
+ }))
347
+ }}
348
+ >
349
+ {done ? 'Undo' : 'Complete today'}
350
+ </FeatureAction>
351
+ </FeatureFrame>
352
+ )
353
+ }
354
+
355
+ export function Poll(input: KowalskiInput<'poll'>) {
356
+ const props = kowalskiCatalog.poll.props.parse(input)
357
+ const options = props.options
358
+ const schema = kowalskiCatalog.poll.storeSchema
359
+ const name = props.id ?? 'KowalskiPoll'
360
+ const identity = useMemo(
361
+ () =>
362
+ `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}`,
363
+ [name]
364
+ )
365
+ const voter = useFeatureStore({
366
+ initialState: { configuration: '', voter: identity },
367
+ name: `${name}Voter`,
368
+ schema: pollVoterSchema,
369
+ scope: 'private',
370
+ })
371
+ const store = useConfiguredFeature({
372
+ name,
373
+ revision: props.revision,
374
+ schema,
375
+ scope: props.shared ? 'public' : 'private',
376
+ seed: schema.parse({}),
377
+ })
378
+ const validIds = new Set(options.map(option => option.id))
379
+ const ballotKey = `vote_${voter.value.voter}`
380
+ const votes = Object.entries(store.value)
381
+ .filter(
382
+ ([key, id]) => key.startsWith('vote_') && typeof id === 'string' && validIds.has(id)
383
+ )
384
+ .map(([, id]) => id)
385
+ const choice = options.find(option => option.id === store.value[ballotKey])
386
+ const notice = store.error ?? voter.error
387
+ const ready = store.ready && voter.ready
388
+ const loading = !ready && !notice
389
+ const percent = format.formatters.getNumberFormat(format.locale, {
390
+ maximumFractionDigits: 1,
391
+ style: 'percent',
392
+ })
393
+ return (
394
+ <FeatureFrame
395
+ onRetry={
396
+ store.retry || voter.retry
397
+ ? () => {
398
+ store.retry?.()
399
+ voter.retry?.()
400
+ }
401
+ : undefined
402
+ }
403
+ notice={notice}
404
+ component="poll"
405
+ title={props.question}
406
+ trailing={
407
+ <Text {...stylex.props(roles.muted)}>
408
+ {loading
409
+ ? 'Loading…'
410
+ : format.formatMessage(
411
+ {
412
+ defaultMessage: '{count, plural, one {# vote} other {# votes}}',
413
+ id: 'kowalski.poll.votes',
414
+ },
415
+ { count: votes.length }
416
+ )}
417
+ </Text>
418
+ }
419
+ >
420
+ <Flex {...stylex.props(pollStyles.options)}>
421
+ {options.map(option => {
422
+ const count = votes.filter(id => id === option.id).length
423
+ const selected = choice?.id === option.id
424
+ const share = votes.length ? count / votes.length : 0
425
+ const shareLabel =
426
+ share > 0 && share < 0.001
427
+ ? '<0.1%'
428
+ : share < 1 && share > 0.999
429
+ ? '>99.9%'
430
+ : percent.format(share)
431
+ return (
432
+ <Button
433
+ key={option.id}
434
+ selected={selected}
435
+ disabled={!ready}
436
+ onClick={() => {
437
+ store.set(() => ({ [ballotKey]: option.id }))
438
+ }}
439
+ style={[button.secondary, pollStyles.option, !ready && button.disabled]}
440
+ >
441
+ <Flex {...stylex.props(pollStyles.optionHeading)}>
442
+ <Flex
443
+ {...stylex.props(
444
+ pollStyles.radio,
445
+ selected && pollStyles.selectedRadio
446
+ )}
447
+ >
448
+ {selected && <Flex {...stylex.props(pollStyles.dot)} />}
449
+ </Flex>
450
+ <Flex {...stylex.props(layout.grow, layout.choiceText)}>
451
+ <Text>{option.label}</Text>
452
+ {selected && (
453
+ <Text {...stylex.props(roles.muted, appearance.accent)}>
454
+ Your vote
455
+ </Text>
456
+ )}
457
+ {votes.length > 0 && (
458
+ <>
459
+ <FeatureProgress component="poll" value={share} />
460
+ <Text {...stylex.props(roles.muted)}>
461
+ {format.formatMessage(
462
+ {
463
+ defaultMessage:
464
+ '{count, plural, one {# vote} other {# votes}} · {share}',
465
+ id: 'kowalski.poll.share',
466
+ },
467
+ { count, share: shareLabel }
468
+ )}
469
+ </Text>
470
+ </>
471
+ )}
472
+ </Flex>
473
+ </Flex>
474
+ </Button>
475
+ )
476
+ })}
477
+ </Flex>
478
+ <Text {...stylex.props(roles.muted)}>
479
+ {ready
480
+ ? store.saving && choice
481
+ ? 'Saving… You can still change your vote.'
482
+ : notice
483
+ ? 'Choose an option to try again.'
484
+ : choice
485
+ ? 'Tap another option to change your vote.'
486
+ : votes.length === 0
487
+ ? 'Be the first to vote. Choose one option.'
488
+ : 'Choose one option to add your vote.'
489
+ : notice
490
+ ? 'Voting is unavailable.'
491
+ : 'Loading your ballot…'}
492
+ </Text>
493
+ </FeatureFrame>
494
+ )
495
+ }
496
+
497
+ const goalStyles = stylex.create({
498
+ controls: { gap: space[2] },
499
+ metric: {
500
+ alignItems: 'baseline',
501
+ flexDirection: 'row',
502
+ flexWrap: 'wrap',
503
+ gap: space[2],
504
+ },
505
+ status: { alignItems: 'center', flexDirection: 'row', gap: space[1.5] },
506
+ value: (length: number) => ({
507
+ fontSize: length > 12 ? text.xl : length > 7 ? text['4xl'] : font.displaySize,
508
+ lineHeight:
509
+ length > 12
510
+ ? text.xlLeading
511
+ : length > 7
512
+ ? text['4xlLeading']
513
+ : font.displayLeading,
514
+ maxWidth: '100%',
515
+ minWidth: 0,
516
+ }),
517
+ })
518
+
519
+ const checklistStyles = stylex.create({
520
+ status: { alignItems: 'center', flexDirection: 'row', gap: space[1.5] },
521
+ })
522
+
523
+ // A week strip: state reads from the date chip alone (filled, plain, or faded).
524
+ const habitStyles = stylex.create({
525
+ completedDate: {
526
+ backgroundColor: colors.accent,
527
+ borderColor: colors.accent,
528
+ color: colors.onAccent,
529
+ },
530
+ date: {
531
+ alignItems: 'center',
532
+ borderRadius: radius.full,
533
+ height: size[9],
534
+ justifyContent: 'center',
535
+ width: size[9],
536
+ },
537
+ day: { alignItems: 'center', flexBasis: '0%', flexGrow: 1, gap: space[2], minWidth: 0 },
538
+ history: { flexDirection: 'row', gap: space[1] },
539
+ offDay: { opacity: 0.5 },
540
+ row: {
541
+ alignItems: 'center',
542
+ flexDirection: 'row',
543
+ flexWrap: 'wrap',
544
+ gap: space[3],
545
+ justifyContent: 'space-between',
546
+ },
547
+ weekday: { flexBasis: '22%', flexGrow: 1, textAlign: 'center' },
548
+ weekdays: { flexDirection: 'row', flexWrap: 'wrap', gap: space[2] },
549
+ })
550
+
551
+ // A real radio: a round size-6 ring, filled with a centred dot when chosen.
552
+ const pollStyles = stylex.create({
553
+ dot: {
554
+ backgroundColor: colors.onAccent,
555
+ borderRadius: radius.full,
556
+ height: size[2],
557
+ width: size[2],
558
+ },
559
+ option: { alignItems: 'stretch', padding: space[3] },
560
+ optionHeading: { alignItems: 'flex-start', flexDirection: 'row', gap: space[3] },
561
+ options: { gap: space[2] },
562
+ radio: {
563
+ alignItems: 'center',
564
+ backgroundColor: colors.surface,
565
+ borderColor: colors.border,
566
+ borderRadius: radius.full,
567
+ borderStyle: 'solid',
568
+ borderWidth: shape.stroke,
569
+ flexShrink: 0,
570
+ height: size[6],
571
+ justifyContent: 'center',
572
+ width: size[6],
573
+ },
574
+ selectedRadio: { backgroundColor: colors.accent, borderColor: colors.accent },
575
+ })