even-toolkit 0.5.2 → 1.0.1

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 (592) hide show
  1. package/README.md +113 -71
  2. package/dist/glasses/action-bar.d.ts.map +1 -0
  3. package/dist/glasses/action-bar.js.map +1 -0
  4. package/dist/glasses/action-map.d.ts.map +1 -0
  5. package/dist/glasses/action-map.js.map +1 -0
  6. package/dist/glasses/bridge.d.ts.map +1 -0
  7. package/dist/glasses/bridge.js.map +1 -0
  8. package/dist/glasses/canvas-renderer.d.ts.map +1 -0
  9. package/dist/glasses/canvas-renderer.js.map +1 -0
  10. package/dist/glasses/composer.d.ts.map +1 -0
  11. package/dist/glasses/composer.js.map +1 -0
  12. package/dist/glasses/gestures.d.ts.map +1 -0
  13. package/dist/glasses/gestures.js.map +1 -0
  14. package/dist/glasses/index.d.ts.map +1 -0
  15. package/dist/glasses/index.js.map +1 -0
  16. package/dist/glasses/keep-alive.d.ts.map +1 -0
  17. package/dist/glasses/keep-alive.js.map +1 -0
  18. package/dist/glasses/keyboard.d.ts.map +1 -0
  19. package/dist/glasses/keyboard.js.map +1 -0
  20. package/dist/glasses/layout.d.ts.map +1 -0
  21. package/dist/glasses/layout.js.map +1 -0
  22. package/dist/glasses/paginate-text.d.ts.map +1 -0
  23. package/dist/glasses/paginate-text.js.map +1 -0
  24. package/dist/glasses/png-utils.d.ts.map +1 -0
  25. package/dist/glasses/png-utils.js.map +1 -0
  26. package/dist/glasses/splash.d.ts.map +1 -0
  27. package/dist/glasses/splash.js.map +1 -0
  28. package/dist/glasses/text-clean.d.ts.map +1 -0
  29. package/dist/glasses/text-clean.js.map +1 -0
  30. package/dist/glasses/text-utils.d.ts.map +1 -0
  31. package/dist/glasses/text-utils.js.map +1 -0
  32. package/dist/glasses/timer-display.d.ts.map +1 -0
  33. package/dist/glasses/timer-display.js.map +1 -0
  34. package/dist/glasses/types.d.ts.map +1 -0
  35. package/dist/glasses/types.js.map +1 -0
  36. package/dist/glasses/useFlashPhase.d.ts.map +1 -0
  37. package/dist/glasses/useFlashPhase.js.map +1 -0
  38. package/dist/glasses/useGlasses.d.ts.map +1 -0
  39. package/dist/glasses/useGlasses.js.map +1 -0
  40. package/dist/web/components/app-shell.d.ts +15 -0
  41. package/dist/web/components/app-shell.d.ts.map +1 -0
  42. package/dist/web/components/app-shell.js +11 -0
  43. package/dist/web/components/app-shell.js.map +1 -0
  44. package/dist/web/components/audio-player.d.ts +9 -0
  45. package/dist/web/components/audio-player.d.ts.map +1 -0
  46. package/dist/web/components/audio-player.js +54 -0
  47. package/dist/web/components/audio-player.js.map +1 -0
  48. package/dist/web/components/badge.d.ts +11 -0
  49. package/dist/web/components/badge.d.ts.map +1 -0
  50. package/dist/web/components/badge.js +21 -0
  51. package/dist/web/components/badge.js.map +1 -0
  52. package/dist/web/components/bottom-sheet.d.ts +11 -0
  53. package/dist/web/components/bottom-sheet.d.ts.map +1 -0
  54. package/dist/web/components/bottom-sheet.js +33 -0
  55. package/dist/web/components/bottom-sheet.js.map +1 -0
  56. package/dist/web/components/button.d.ts +12 -0
  57. package/dist/web/components/button.d.ts.map +1 -0
  58. package/dist/web/components/button.js +29 -0
  59. package/dist/web/components/button.js.map +1 -0
  60. package/dist/web/components/calendar.d.ts +48 -0
  61. package/dist/web/components/calendar.d.ts.map +1 -0
  62. package/dist/web/components/calendar.js +86 -0
  63. package/dist/web/components/calendar.js.map +1 -0
  64. package/dist/web/components/card.d.ts +12 -0
  65. package/dist/web/components/card.d.ts.map +1 -0
  66. package/dist/web/components/card.js +27 -0
  67. package/dist/web/components/card.js.map +1 -0
  68. package/dist/web/components/category-filter.d.ts +10 -0
  69. package/dist/web/components/category-filter.d.ts.map +1 -0
  70. package/dist/web/components/category-filter.js +9 -0
  71. package/dist/web/components/category-filter.js.map +1 -0
  72. package/dist/web/components/chart.d.ts +65 -0
  73. package/dist/web/components/chart.d.ts.map +1 -0
  74. package/dist/web/components/chart.js +62 -0
  75. package/dist/web/components/chart.js.map +1 -0
  76. package/dist/web/components/chat.d.ts +79 -0
  77. package/dist/web/components/chat.d.ts.map +1 -0
  78. package/dist/web/components/chat.js +166 -0
  79. package/dist/web/components/chat.js.map +1 -0
  80. package/dist/web/components/checkbox.d.ts +11 -0
  81. package/dist/web/components/checkbox.d.ts.map +1 -0
  82. package/dist/web/components/checkbox.js +7 -0
  83. package/dist/web/components/checkbox.js.map +1 -0
  84. package/dist/web/components/confirm-dialog.d.ts +14 -0
  85. package/dist/web/components/confirm-dialog.d.ts.map +1 -0
  86. package/dist/web/components/confirm-dialog.js +37 -0
  87. package/dist/web/components/confirm-dialog.js.map +1 -0
  88. package/dist/web/components/cta-group.d.ts +16 -0
  89. package/dist/web/components/cta-group.d.ts.map +1 -0
  90. package/dist/web/components/cta-group.js +22 -0
  91. package/dist/web/components/cta-group.js.map +1 -0
  92. package/dist/web/components/dialog.d.ts +19 -0
  93. package/dist/web/components/dialog.d.ts.map +1 -0
  94. package/dist/web/components/dialog.js +35 -0
  95. package/dist/web/components/dialog.js.map +1 -0
  96. package/dist/web/components/divider.d.ts +11 -0
  97. package/dist/web/components/divider.d.ts.map +1 -0
  98. package/dist/web/components/divider.js +19 -0
  99. package/dist/web/components/divider.js.map +1 -0
  100. package/dist/web/components/empty-state.d.ts +15 -0
  101. package/dist/web/components/empty-state.d.ts.map +1 -0
  102. package/dist/web/components/empty-state.js +7 -0
  103. package/dist/web/components/empty-state.js.map +1 -0
  104. package/dist/web/components/file-upload.d.ts +12 -0
  105. package/dist/web/components/file-upload.d.ts.map +1 -0
  106. package/dist/web/components/file-upload.js +38 -0
  107. package/dist/web/components/file-upload.js.map +1 -0
  108. package/dist/web/components/image-viewer.d.ts +23 -0
  109. package/dist/web/components/image-viewer.d.ts.map +1 -0
  110. package/dist/web/components/image-viewer.js +29 -0
  111. package/dist/web/components/image-viewer.js.map +1 -0
  112. package/dist/web/components/indicator.d.ts +15 -0
  113. package/dist/web/components/indicator.d.ts.map +1 -0
  114. package/dist/web/components/indicator.js +12 -0
  115. package/dist/web/components/indicator.js.map +1 -0
  116. package/dist/web/components/input-group.d.ts +9 -0
  117. package/dist/web/components/input-group.d.ts.map +1 -0
  118. package/dist/web/components/input-group.js +27 -0
  119. package/dist/web/components/input-group.js.map +1 -0
  120. package/dist/web/components/input.d.ts +7 -0
  121. package/dist/web/components/input.d.ts.map +1 -0
  122. package/dist/web/components/input.js +7 -0
  123. package/dist/web/components/input.js.map +1 -0
  124. package/dist/web/components/kbd.d.ts +9 -0
  125. package/dist/web/components/kbd.d.ts.map +1 -0
  126. package/dist/web/components/kbd.js +7 -0
  127. package/dist/web/components/kbd.js.map +1 -0
  128. package/dist/web/components/list-item.d.ts +14 -0
  129. package/dist/web/components/list-item.d.ts.map +1 -0
  130. package/dist/web/components/list-item.js +57 -0
  131. package/dist/web/components/list-item.js.map +1 -0
  132. package/dist/web/components/loading.d.ts +8 -0
  133. package/dist/web/components/loading.d.ts.map +1 -0
  134. package/dist/web/components/loading.js +41 -0
  135. package/dist/web/components/loading.js.map +1 -0
  136. package/dist/web/components/nav-bar.d.ts +14 -0
  137. package/dist/web/components/nav-bar.d.ts.map +1 -0
  138. package/dist/web/components/nav-bar.js +9 -0
  139. package/dist/web/components/nav-bar.js.map +1 -0
  140. package/dist/web/components/nav-header.d.ts +11 -0
  141. package/dist/web/components/nav-header.d.ts.map +1 -0
  142. package/dist/web/components/nav-header.js +7 -0
  143. package/dist/web/components/nav-header.js.map +1 -0
  144. package/dist/web/components/page.d.ts +9 -0
  145. package/dist/web/components/page.d.ts.map +1 -0
  146. package/dist/web/components/page.js +7 -0
  147. package/dist/web/components/page.js.map +1 -0
  148. package/dist/web/components/pill.d.ts +9 -0
  149. package/dist/web/components/pill.d.ts.map +1 -0
  150. package/dist/web/components/pill.js +7 -0
  151. package/dist/web/components/pill.js.map +1 -0
  152. package/dist/web/components/progress.d.ts +8 -0
  153. package/dist/web/components/progress.d.ts.map +1 -0
  154. package/dist/web/components/progress.js +7 -0
  155. package/dist/web/components/progress.js.map +1 -0
  156. package/dist/web/components/radio-group.d.ts +16 -0
  157. package/dist/web/components/radio-group.d.ts.map +1 -0
  158. package/dist/web/components/radio-group.js +10 -0
  159. package/dist/web/components/radio-group.js.map +1 -0
  160. package/dist/web/components/screen-header.d.ts +11 -0
  161. package/dist/web/components/screen-header.d.ts.map +1 -0
  162. package/dist/web/components/screen-header.js +7 -0
  163. package/dist/web/components/screen-header.js.map +1 -0
  164. package/dist/web/components/scroll-picker.d.ts +66 -0
  165. package/dist/web/components/scroll-picker.d.ts.map +1 -0
  166. package/dist/web/components/scroll-picker.js +243 -0
  167. package/dist/web/components/scroll-picker.js.map +1 -0
  168. package/dist/web/components/search-bar.d.ts +9 -0
  169. package/dist/web/components/search-bar.d.ts.map +1 -0
  170. package/dist/web/components/search-bar.js +8 -0
  171. package/dist/web/components/search-bar.js.map +1 -0
  172. package/dist/web/components/section-header.d.ts +10 -0
  173. package/dist/web/components/section-header.d.ts.map +1 -0
  174. package/dist/web/components/section-header.js +7 -0
  175. package/dist/web/components/section-header.js.map +1 -0
  176. package/dist/web/components/segmented-control.d.ts +15 -0
  177. package/dist/web/components/segmented-control.d.ts.map +1 -0
  178. package/dist/web/components/segmented-control.js +9 -0
  179. package/dist/web/components/segmented-control.js.map +1 -0
  180. package/dist/web/components/select.d.ts +13 -0
  181. package/dist/web/components/select.d.ts.map +1 -0
  182. package/dist/web/components/select.js +7 -0
  183. package/dist/web/components/select.js.map +1 -0
  184. package/dist/web/components/settings-group.d.ts +10 -0
  185. package/dist/web/components/settings-group.d.ts.map +1 -0
  186. package/dist/web/components/settings-group.js +7 -0
  187. package/dist/web/components/settings-group.js.map +1 -0
  188. package/dist/web/components/skeleton.d.ts +13 -0
  189. package/dist/web/components/skeleton.d.ts.map +1 -0
  190. package/dist/web/components/skeleton.js +23 -0
  191. package/dist/web/components/skeleton.js.map +1 -0
  192. package/dist/web/components/slider.d.ts +16 -0
  193. package/dist/web/components/slider.d.ts.map +1 -0
  194. package/dist/web/components/slider.js +8 -0
  195. package/dist/web/components/slider.js.map +1 -0
  196. package/dist/web/components/stat-grid.d.ts +14 -0
  197. package/dist/web/components/stat-grid.d.ts.map +1 -0
  198. package/dist/web/components/stat-grid.js +7 -0
  199. package/dist/web/components/stat-grid.js.map +1 -0
  200. package/dist/web/components/status-dot.d.ts +8 -0
  201. package/dist/web/components/status-dot.d.ts.map +1 -0
  202. package/dist/web/components/status-dot.js +7 -0
  203. package/dist/web/components/status-dot.js.map +1 -0
  204. package/dist/web/components/status-progress.d.ts +13 -0
  205. package/dist/web/components/status-progress.d.ts.map +1 -0
  206. package/dist/web/components/status-progress.js +7 -0
  207. package/dist/web/components/status-progress.js.map +1 -0
  208. package/dist/web/components/step-indicator.d.ts +13 -0
  209. package/dist/web/components/step-indicator.d.ts.map +1 -0
  210. package/dist/web/components/step-indicator.js +10 -0
  211. package/dist/web/components/step-indicator.js.map +1 -0
  212. package/dist/web/components/table.d.ts +9 -0
  213. package/dist/web/components/table.d.ts.map +1 -0
  214. package/dist/web/components/table.js +17 -0
  215. package/dist/web/components/table.js.map +1 -0
  216. package/dist/web/components/tag.d.ts +25 -0
  217. package/dist/web/components/tag.d.ts.map +1 -0
  218. package/dist/web/components/tag.js +15 -0
  219. package/dist/web/components/tag.js.map +1 -0
  220. package/dist/web/components/textarea.d.ts +7 -0
  221. package/dist/web/components/textarea.d.ts.map +1 -0
  222. package/dist/web/components/textarea.js +7 -0
  223. package/dist/web/components/textarea.js.map +1 -0
  224. package/dist/web/components/timeline.d.ts +17 -0
  225. package/dist/web/components/timeline.d.ts.map +1 -0
  226. package/dist/web/components/timeline.js +7 -0
  227. package/dist/web/components/timeline.js.map +1 -0
  228. package/dist/web/components/timer-ring.d.ts +12 -0
  229. package/dist/web/components/timer-ring.d.ts.map +1 -0
  230. package/dist/web/components/timer-ring.js +15 -0
  231. package/dist/web/components/timer-ring.js.map +1 -0
  232. package/dist/web/components/toast.d.ts +14 -0
  233. package/dist/web/components/toast.d.ts.map +1 -0
  234. package/dist/web/components/toast.js +21 -0
  235. package/dist/web/components/toast.js.map +1 -0
  236. package/dist/web/components/toggle.d.ts +10 -0
  237. package/dist/web/components/toggle.d.ts.map +1 -0
  238. package/dist/web/components/toggle.js +21 -0
  239. package/dist/web/components/toggle.js.map +1 -0
  240. package/dist/web/components/voice-input.d.ts +17 -0
  241. package/dist/web/components/voice-input.d.ts.map +1 -0
  242. package/dist/web/components/voice-input.js +60 -0
  243. package/dist/web/components/voice-input.js.map +1 -0
  244. package/dist/web/icons/index.d.ts +29 -0
  245. package/dist/web/icons/index.d.ts.map +1 -0
  246. package/dist/web/icons/index.js +47 -0
  247. package/dist/web/icons/index.js.map +1 -0
  248. package/dist/web/icons/svg-catalog.d.ts +7 -0
  249. package/dist/web/icons/svg-catalog.d.ts.map +1 -0
  250. package/dist/web/icons/svg-catalog.js +1389 -0
  251. package/dist/web/icons/svg-catalog.js.map +1 -0
  252. package/dist/web/icons/svg-icons.d.ts +207 -0
  253. package/dist/web/icons/svg-icons.d.ts.map +1 -0
  254. package/dist/web/icons/svg-icons.js +398 -0
  255. package/dist/web/icons/svg-icons.js.map +1 -0
  256. package/dist/web/index.d.ts +107 -0
  257. package/dist/web/index.d.ts.map +1 -0
  258. package/dist/web/index.js +69 -0
  259. package/dist/web/index.js.map +1 -0
  260. package/dist/web/utils/cn.d.ts +3 -0
  261. package/dist/web/utils/cn.d.ts.map +1 -0
  262. package/dist/web/utils/cn.js +6 -0
  263. package/dist/web/utils/cn.js.map +1 -0
  264. package/package.json +289 -46
  265. package/web/components/app-shell.tsx +29 -0
  266. package/web/components/audio-player.tsx +117 -0
  267. package/web/components/badge.tsx +39 -0
  268. package/web/components/bottom-sheet.tsx +61 -0
  269. package/web/components/button.tsx +48 -0
  270. package/web/components/calendar.tsx +333 -0
  271. package/web/components/card.tsx +42 -0
  272. package/web/components/category-filter.tsx +33 -0
  273. package/web/components/chart.tsx +411 -0
  274. package/web/components/chat.tsx +494 -0
  275. package/web/components/checkbox.tsx +52 -0
  276. package/web/components/confirm-dialog.tsx +100 -0
  277. package/web/components/cta-group.tsx +85 -0
  278. package/web/components/dialog.tsx +94 -0
  279. package/web/components/divider.tsx +25 -0
  280. package/web/components/empty-state.tsx +32 -0
  281. package/web/components/file-upload.tsx +100 -0
  282. package/web/components/image-viewer.tsx +131 -0
  283. package/web/components/indicator.tsx +50 -0
  284. package/web/components/input-group.tsx +39 -0
  285. package/web/components/input.tsx +23 -0
  286. package/web/components/kbd.tsx +22 -0
  287. package/web/components/list-item.tsx +106 -0
  288. package/web/components/loading.tsx +79 -0
  289. package/web/components/nav-bar.tsx +43 -0
  290. package/web/components/nav-header.tsx +24 -0
  291. package/web/components/page.tsx +14 -0
  292. package/web/components/pill.tsx +32 -0
  293. package/web/components/progress.tsx +26 -0
  294. package/web/components/radio-group.tsx +59 -0
  295. package/web/components/screen-header.tsx +26 -0
  296. package/web/components/scroll-picker.tsx +508 -0
  297. package/web/components/search-bar.tsx +28 -0
  298. package/web/components/section-header.tsx +20 -0
  299. package/web/components/segmented-control.tsx +50 -0
  300. package/web/components/select.tsx +37 -0
  301. package/web/components/settings-group.tsx +22 -0
  302. package/web/components/skeleton.tsx +36 -0
  303. package/web/components/slider.tsx +69 -0
  304. package/web/components/stat-grid.tsx +40 -0
  305. package/web/components/status-dot.tsx +21 -0
  306. package/web/components/status-progress.tsx +56 -0
  307. package/web/components/step-indicator.tsx +52 -0
  308. package/web/components/table.tsx +70 -0
  309. package/web/components/tag.tsx +72 -0
  310. package/web/components/textarea.tsx +23 -0
  311. package/web/components/timeline.tsx +52 -0
  312. package/web/components/timer-ring.tsx +69 -0
  313. package/web/components/toast.tsx +38 -0
  314. package/web/components/toggle.tsx +58 -0
  315. package/web/components/voice-input.tsx +165 -0
  316. package/web/icons/README.md +38 -0
  317. package/web/icons/index.ts +61 -0
  318. package/web/icons/svg/edit-add.svg +13 -0
  319. package/web/icons/svg/edit-checklist.svg +3 -0
  320. package/web/icons/svg/edit-copy.svg +12 -0
  321. package/web/icons/svg/edit-cross-small.svg +10 -0
  322. package/web/icons/svg/edit-cross.svg +10 -0
  323. package/web/icons/svg/edit-cut.svg +10 -0
  324. package/web/icons/svg/edit-display-adj.svg +3 -0
  325. package/web/icons/svg/edit-dist-adj.svg +3 -0
  326. package/web/icons/svg/edit-dot-lists.svg +3 -0
  327. package/web/icons/svg/edit-edit.svg +3 -0
  328. package/web/icons/svg/edit-hight-adj.svg +3 -0
  329. package/web/icons/svg/edit-import.svg +10 -0
  330. package/web/icons/svg/edit-layout-settings.svg +10 -0
  331. package/web/icons/svg/edit-multi-selection.svg +10 -0
  332. package/web/icons/svg/edit-new.svg +3 -0
  333. package/web/icons/svg/edit-number-list.svg +3 -0
  334. package/web/icons/svg/edit-options.svg +10 -0
  335. package/web/icons/svg/edit-paste.svg +10 -0
  336. package/web/icons/svg/edit-pause.svg +10 -0
  337. package/web/icons/svg/edit-pin.svg +10 -0
  338. package/web/icons/svg/edit-play.svg +10 -0
  339. package/web/icons/svg/edit-redo.svg +10 -0
  340. package/web/icons/svg/edit-restore.svg +10 -0
  341. package/web/icons/svg/edit-settings.svg +3 -0
  342. package/web/icons/svg/edit-share.svg +3 -0
  343. package/web/icons/svg/edit-sweep.svg +10 -0
  344. package/web/icons/svg/edit-switch.svg +3 -0
  345. package/web/icons/svg/edit-trash.svg +10 -0
  346. package/web/icons/svg/edit-undo.svg +10 -0
  347. package/web/icons/svg/edit-unpin.svg +3 -0
  348. package/web/icons/svg/edit-upload-to-cloud.svg +3 -0
  349. package/web/icons/svg/edit-width.svg +3 -0
  350. package/web/icons/svg/feat-access-control.svg +10 -0
  351. package/web/icons/svg/feat-account.svg +10 -0
  352. package/web/icons/svg/feat-calendar.svg +3 -0
  353. package/web/icons/svg/feat-camera.svg +3 -0
  354. package/web/icons/svg/feat-direct-push.svg +3 -0
  355. package/web/icons/svg/feat-eis.svg +10 -0
  356. package/web/icons/svg/feat-email.svg +10 -0
  357. package/web/icons/svg/feat-even-ai.svg +3 -0
  358. package/web/icons/svg/feat-facial-scan.svg +3 -0
  359. package/web/icons/svg/feat-feedback.svg +3 -0
  360. package/web/icons/svg/feat-headup-angle.svg +10 -0
  361. package/web/icons/svg/feat-inbox.svg +10 -0
  362. package/web/icons/svg/feat-interface-settings.svg +3 -0
  363. package/web/icons/svg/feat-languages.svg +10 -0
  364. package/web/icons/svg/feat-learn-explore.svg +3 -0
  365. package/web/icons/svg/feat-menu.svg +3 -0
  366. package/web/icons/svg/feat-message.svg +10 -0
  367. package/web/icons/svg/feat-navigate.svg +10 -0
  368. package/web/icons/svg/feat-news.svg +10 -0
  369. package/web/icons/svg/feat-notification.svg +10 -0
  370. package/web/icons/svg/feat-personal-info.svg +10 -0
  371. package/web/icons/svg/feat-phone-call.svg +10 -0
  372. package/web/icons/svg/feat-phone-voice-input.svg +3 -0
  373. package/web/icons/svg/feat-privacy.svg +3 -0
  374. package/web/icons/svg/feat-qr-code.svg +3 -0
  375. package/web/icons/svg/feat-quick-note.svg +3 -0
  376. package/web/icons/svg/feat-scan.svg +3 -0
  377. package/web/icons/svg/feat-screen-off.svg +16 -0
  378. package/web/icons/svg/feat-services.svg +3 -0
  379. package/web/icons/svg/feat-stocks.svg +10 -0
  380. package/web/icons/svg/feat-study.svg +10 -0
  381. package/web/icons/svg/feat-teleprompt.svg +3 -0
  382. package/web/icons/svg/feat-theme.svg +10 -0
  383. package/web/icons/svg/feat-time-counting.svg +10 -0
  384. package/web/icons/svg/feat-transcribe.svg +3 -0
  385. package/web/icons/svg/feat-translate.svg +3 -0
  386. package/web/icons/svg/feat-voice-print.svg +10 -0
  387. package/web/icons/svg/feat-wear-detect.svg +3 -0
  388. package/web/icons/svg/feat-weather.svg +10 -0
  389. package/web/icons/svg/feat-wiki.svg +3 -0
  390. package/web/icons/svg/guide-back.svg +10 -0
  391. package/web/icons/svg/guide-chevron-drill-back.svg +10 -0
  392. package/web/icons/svg/guide-chevron-drill-down.svg +10 -0
  393. package/web/icons/svg/guide-chevron-drill-up.svg +10 -0
  394. package/web/icons/svg/guide-chevron-small-back.svg +10 -0
  395. package/web/icons/svg/guide-chevron-small-drill-back.svg +3 -0
  396. package/web/icons/svg/guide-chevron-small-drill-down.svg +10 -0
  397. package/web/icons/svg/guide-chevron-small-drill-in.svg +3 -0
  398. package/web/icons/svg/guide-chevron-small-drill-up.svg +10 -0
  399. package/web/icons/svg/guide-double-tap.svg +3 -0
  400. package/web/icons/svg/guide-go.svg +10 -0
  401. package/web/icons/svg/guide-long-press.svg +3 -0
  402. package/web/icons/svg/guide-maximize-card.svg +10 -0
  403. package/web/icons/svg/guide-maximize.svg +10 -0
  404. package/web/icons/svg/guide-minimize-card.svg +10 -0
  405. package/web/icons/svg/guide-minimize.svg +3 -0
  406. package/web/icons/svg/guide-search.svg +3 -0
  407. package/web/icons/svg/guide-shift-to-top.svg +10 -0
  408. package/web/icons/svg/guide-single-tap.svg +3 -0
  409. package/web/icons/svg/guide-swip.svg +3 -0
  410. package/web/icons/svg/health-HRV.svg +3 -0
  411. package/web/icons/svg/health-heart-rate.svg +3 -0
  412. package/web/icons/svg/health-lift-2.svg +3 -0
  413. package/web/icons/svg/health-lift-3.svg +3 -0
  414. package/web/icons/svg/health-lift.svg +3 -0
  415. package/web/icons/svg/health-run.svg +3 -0
  416. package/web/icons/svg/health-sleep.svg +10 -0
  417. package/web/icons/svg/health-spo2.svg +7 -0
  418. package/web/icons/svg/health-stand.svg +3 -0
  419. package/web/icons/svg/health-steps.svg +10 -0
  420. package/web/icons/svg/health-temperature.svg +3 -0
  421. package/web/icons/svg/health-walk.svg +3 -0
  422. package/web/icons/svg/menu-even-hub-highlighted.svg +10 -0
  423. package/web/icons/svg/menu-even-hub.svg +10 -0
  424. package/web/icons/svg/menu-gear-highlighted.svg +10 -0
  425. package/web/icons/svg/menu-gear.svg +10 -0
  426. package/web/icons/svg/menu-healt-highlighted.svg +10 -0
  427. package/web/icons/svg/menu-healt.svg +10 -0
  428. package/web/icons/svg/menu-home-highlighted.svg +10 -0
  429. package/web/icons/svg/menu-home.svg +10 -0
  430. package/web/icons/svg/nav-bicycle.svg +10 -0
  431. package/web/icons/svg/nav-bus.svg +10 -0
  432. package/web/icons/svg/nav-business.svg +10 -0
  433. package/web/icons/svg/nav-cloth-shop.svg +10 -0
  434. package/web/icons/svg/nav-coffee-shop.svg +10 -0
  435. package/web/icons/svg/nav-compass.svg +3 -0
  436. package/web/icons/svg/nav-crown.svg +3 -0
  437. package/web/icons/svg/nav-direction.svg +10 -0
  438. package/web/icons/svg/nav-end-location.svg +3 -0
  439. package/web/icons/svg/nav-flag.svg +3 -0
  440. package/web/icons/svg/nav-gift.svg +3 -0
  441. package/web/icons/svg/nav-groceries.svg +10 -0
  442. package/web/icons/svg/nav-home-address.svg +10 -0
  443. package/web/icons/svg/nav-hotel.svg +10 -0
  444. package/web/icons/svg/nav-location.svg +3 -0
  445. package/web/icons/svg/nav-office-address.svg +10 -0
  446. package/web/icons/svg/nav-relocate.svg +10 -0
  447. package/web/icons/svg/nav-restaurant.svg +10 -0
  448. package/web/icons/svg/nav-shopping.svg +3 -0
  449. package/web/icons/svg/nav-train.svg +10 -0
  450. package/web/icons/svg/nav-walk.svg +3 -0
  451. package/web/icons/svg/nav-zoom-in.svg +3 -0
  452. package/web/icons/svg/nav-zoom-out.svg +3 -0
  453. package/web/icons/svg/status-alert.svg +5 -0
  454. package/web/icons/svg/status-archived-file.svg +3 -0
  455. package/web/icons/svg/status-bad-pressed.svg +23 -0
  456. package/web/icons/svg/status-bad.svg +20 -0
  457. package/web/icons/svg/status-battery-50.svg +10 -0
  458. package/web/icons/svg/status-battery-75.svg +10 -0
  459. package/web/icons/svg/status-battery-dying.svg +15 -0
  460. package/web/icons/svg/status-battery-full.svg +10 -0
  461. package/web/icons/svg/status-battery-low.svg +10 -0
  462. package/web/icons/svg/status-bluetooth-disconnected.svg +3 -0
  463. package/web/icons/svg/status-bluetooth.svg +10 -0
  464. package/web/icons/svg/status-brightness-auto.svg +3 -0
  465. package/web/icons/svg/status-brightness.svg +3 -0
  466. package/web/icons/svg/status-case-battery.svg +3 -0
  467. package/web/icons/svg/status-case-charging.svg +14 -0
  468. package/web/icons/svg/status-case.svg +3 -0
  469. package/web/icons/svg/status-checkbox.svg +3 -0
  470. package/web/icons/svg/status-checkmark.svg +3 -0
  471. package/web/icons/svg/status-clickbox.svg +3 -0
  472. package/web/icons/svg/status-complete.svg +10 -0
  473. package/web/icons/svg/status-disconnected.svg +10 -0
  474. package/web/icons/svg/status-display-adj-off.svg +11 -0
  475. package/web/icons/svg/status-dot.svg +10 -0
  476. package/web/icons/svg/status-eye-closed.svg +3 -0
  477. package/web/icons/svg/status-eye-open.svg +3 -0
  478. package/web/icons/svg/status-faqs.svg +10 -0
  479. package/web/icons/svg/status-fast.svg +3 -0
  480. package/web/icons/svg/status-fav.svg +29 -0
  481. package/web/icons/svg/status-file.svg +10 -0
  482. package/web/icons/svg/status-first-floor.svg +3 -0
  483. package/web/icons/svg/status-glasses-battery.svg +3 -0
  484. package/web/icons/svg/status-glasses-charging.svg +17 -0
  485. package/web/icons/svg/status-glasses.svg +3 -0
  486. package/web/icons/svg/status-good-pressed.svg +29 -0
  487. package/web/icons/svg/status-good.svg +20 -0
  488. package/web/icons/svg/status-grabber.svg +10 -0
  489. package/web/icons/svg/status-head-up.svg +3 -0
  490. package/web/icons/svg/status-hint.svg +14 -0
  491. package/web/icons/svg/status-info.svg +10 -0
  492. package/web/icons/svg/status-login.svg +10 -0
  493. package/web/icons/svg/status-logout.svg +10 -0
  494. package/web/icons/svg/status-more.svg +3 -0
  495. package/web/icons/svg/status-network-error.svg +3 -0
  496. package/web/icons/svg/status-reset.svg +3 -0
  497. package/web/icons/svg/status-saved.svg +10 -0
  498. package/web/icons/svg/status-second-floor.svg +3 -0
  499. package/web/icons/svg/status-sele.svg +3 -0
  500. package/web/icons/svg/status-selected-box.svg +3 -0
  501. package/web/icons/svg/status-selected.svg +3 -0
  502. package/web/icons/svg/status-slow.svg +3 -0
  503. package/web/icons/svg/status-speaker-off.svg +3 -0
  504. package/web/icons/svg/status-speaker-on.svg +3 -0
  505. package/web/icons/svg/status-text-sizing.svg +3 -0
  506. package/web/icons/svg/status-unbind.svg +10 -0
  507. package/web/icons/svg/status-undisturb.svg +10 -0
  508. package/web/icons/svg/status-unfav.svg +3 -0
  509. package/web/icons/svg-catalog.ts +1390 -0
  510. package/web/icons/svg-icons.tsx +2166 -0
  511. package/web/index.ts +172 -0
  512. package/web/theme/tokens-dark.css +46 -0
  513. package/web/theme/tokens-light.css +46 -0
  514. package/web/theme/typography.css +57 -0
  515. package/web/theme/utilities.css +46 -0
  516. package/web/utils/cn.ts +6 -0
  517. package/dist/action-bar.d.ts.map +0 -1
  518. package/dist/action-bar.js.map +0 -1
  519. package/dist/action-map.d.ts.map +0 -1
  520. package/dist/action-map.js.map +0 -1
  521. package/dist/bridge.d.ts.map +0 -1
  522. package/dist/bridge.js.map +0 -1
  523. package/dist/canvas-renderer.d.ts.map +0 -1
  524. package/dist/canvas-renderer.js.map +0 -1
  525. package/dist/composer.d.ts.map +0 -1
  526. package/dist/composer.js.map +0 -1
  527. package/dist/gestures.d.ts.map +0 -1
  528. package/dist/gestures.js.map +0 -1
  529. package/dist/index.d.ts.map +0 -1
  530. package/dist/index.js.map +0 -1
  531. package/dist/keep-alive.d.ts.map +0 -1
  532. package/dist/keep-alive.js.map +0 -1
  533. package/dist/keyboard.d.ts.map +0 -1
  534. package/dist/keyboard.js.map +0 -1
  535. package/dist/layout.d.ts.map +0 -1
  536. package/dist/layout.js.map +0 -1
  537. package/dist/paginate-text.d.ts.map +0 -1
  538. package/dist/paginate-text.js.map +0 -1
  539. package/dist/png-utils.d.ts.map +0 -1
  540. package/dist/png-utils.js.map +0 -1
  541. package/dist/splash.d.ts.map +0 -1
  542. package/dist/splash.js.map +0 -1
  543. package/dist/text-clean.d.ts.map +0 -1
  544. package/dist/text-clean.js.map +0 -1
  545. package/dist/text-utils.d.ts.map +0 -1
  546. package/dist/text-utils.js.map +0 -1
  547. package/dist/timer-display.d.ts.map +0 -1
  548. package/dist/timer-display.js.map +0 -1
  549. package/dist/types.d.ts.map +0 -1
  550. package/dist/types.js.map +0 -1
  551. package/dist/useFlashPhase.d.ts.map +0 -1
  552. package/dist/useFlashPhase.js.map +0 -1
  553. package/dist/useGlasses.d.ts.map +0 -1
  554. package/dist/useGlasses.js.map +0 -1
  555. /package/dist/{action-bar.d.ts → glasses/action-bar.d.ts} +0 -0
  556. /package/dist/{action-bar.js → glasses/action-bar.js} +0 -0
  557. /package/dist/{action-map.d.ts → glasses/action-map.d.ts} +0 -0
  558. /package/dist/{action-map.js → glasses/action-map.js} +0 -0
  559. /package/dist/{bridge.d.ts → glasses/bridge.d.ts} +0 -0
  560. /package/dist/{bridge.js → glasses/bridge.js} +0 -0
  561. /package/dist/{canvas-renderer.d.ts → glasses/canvas-renderer.d.ts} +0 -0
  562. /package/dist/{canvas-renderer.js → glasses/canvas-renderer.js} +0 -0
  563. /package/dist/{composer.d.ts → glasses/composer.d.ts} +0 -0
  564. /package/dist/{composer.js → glasses/composer.js} +0 -0
  565. /package/dist/{gestures.d.ts → glasses/gestures.d.ts} +0 -0
  566. /package/dist/{gestures.js → glasses/gestures.js} +0 -0
  567. /package/dist/{index.d.ts → glasses/index.d.ts} +0 -0
  568. /package/dist/{index.js → glasses/index.js} +0 -0
  569. /package/dist/{keep-alive.d.ts → glasses/keep-alive.d.ts} +0 -0
  570. /package/dist/{keep-alive.js → glasses/keep-alive.js} +0 -0
  571. /package/dist/{keyboard.d.ts → glasses/keyboard.d.ts} +0 -0
  572. /package/dist/{keyboard.js → glasses/keyboard.js} +0 -0
  573. /package/dist/{layout.d.ts → glasses/layout.d.ts} +0 -0
  574. /package/dist/{layout.js → glasses/layout.js} +0 -0
  575. /package/dist/{paginate-text.d.ts → glasses/paginate-text.d.ts} +0 -0
  576. /package/dist/{paginate-text.js → glasses/paginate-text.js} +0 -0
  577. /package/dist/{png-utils.d.ts → glasses/png-utils.d.ts} +0 -0
  578. /package/dist/{png-utils.js → glasses/png-utils.js} +0 -0
  579. /package/dist/{splash.d.ts → glasses/splash.d.ts} +0 -0
  580. /package/dist/{splash.js → glasses/splash.js} +0 -0
  581. /package/dist/{text-clean.d.ts → glasses/text-clean.d.ts} +0 -0
  582. /package/dist/{text-clean.js → glasses/text-clean.js} +0 -0
  583. /package/dist/{text-utils.d.ts → glasses/text-utils.d.ts} +0 -0
  584. /package/dist/{text-utils.js → glasses/text-utils.js} +0 -0
  585. /package/dist/{timer-display.d.ts → glasses/timer-display.d.ts} +0 -0
  586. /package/dist/{timer-display.js → glasses/timer-display.js} +0 -0
  587. /package/dist/{types.d.ts → glasses/types.d.ts} +0 -0
  588. /package/dist/{types.js → glasses/types.js} +0 -0
  589. /package/dist/{useFlashPhase.d.ts → glasses/useFlashPhase.d.ts} +0 -0
  590. /package/dist/{useFlashPhase.js → glasses/useFlashPhase.js} +0 -0
  591. /package/dist/{useGlasses.d.ts → glasses/useGlasses.d.ts} +0 -0
  592. /package/dist/{useGlasses.js → glasses/useGlasses.js} +0 -0
@@ -0,0 +1,508 @@
1
+ import * as React from 'react';
2
+ import { cn } from '../utils/cn';
3
+
4
+ /* -------------------------------------------------------------------------- */
5
+ /* Types */
6
+ /* -------------------------------------------------------------------------- */
7
+
8
+ interface ScrollColumn {
9
+ options: { value: string; label: string }[];
10
+ separator?: string;
11
+ }
12
+
13
+ interface ScrollPickerProps {
14
+ open: boolean;
15
+ onClose: () => void;
16
+ title: string;
17
+ columns: ScrollColumn[];
18
+ value: string[];
19
+ onValueChange: (value: string[]) => void;
20
+ }
21
+
22
+ interface DatePickerProps {
23
+ open: boolean;
24
+ onClose: () => void;
25
+ title?: string;
26
+ value: { day: number; month: number; year: number };
27
+ onValueChange: (value: { day: number; month: number; year: number }) => void;
28
+ minYear?: number;
29
+ maxYear?: number;
30
+ }
31
+
32
+ interface TimePickerProps {
33
+ open: boolean;
34
+ onClose: () => void;
35
+ title?: string;
36
+ value: { hour: number; minute: number; period?: 'AM' | 'PM' };
37
+ onValueChange: (value: { hour: number; minute: number; period?: 'AM' | 'PM' }) => void;
38
+ format?: '12h' | '24h';
39
+ }
40
+
41
+ interface SelectionPickerProps {
42
+ open: boolean;
43
+ onClose: () => void;
44
+ title?: string;
45
+ options: { value: string; label: string }[];
46
+ value: string;
47
+ onValueChange: (value: string) => void;
48
+ }
49
+
50
+ /* -------------------------------------------------------------------------- */
51
+ /* Constants */
52
+ /* -------------------------------------------------------------------------- */
53
+
54
+ const ITEM_HEIGHT = 40;
55
+ const VISIBLE_ITEMS = 5;
56
+ const CONTAINER_HEIGHT = ITEM_HEIGHT * VISIBLE_ITEMS; // 200px
57
+ const PADDING_ITEMS = 2;
58
+ const PADDING_HEIGHT = ITEM_HEIGHT * PADDING_ITEMS; // 80px
59
+ const SCROLL_DEBOUNCE = 100;
60
+
61
+ /* -------------------------------------------------------------------------- */
62
+ /* ScrollColumn component */
63
+ /* -------------------------------------------------------------------------- */
64
+
65
+ interface ColumnProps {
66
+ options: { value: string; label: string }[];
67
+ selectedValue: string;
68
+ onChange: (value: string) => void;
69
+ }
70
+
71
+ function Column({ options, selectedValue, onChange }: ColumnProps) {
72
+ const containerRef = React.useRef<HTMLDivElement>(null);
73
+ const isUserScrolling = React.useRef(false);
74
+ const scrollTimer = React.useRef<ReturnType<typeof setTimeout> | null>(null);
75
+ const isMounted = React.useRef(true);
76
+
77
+ const selectedIndex = React.useMemo(
78
+ () => Math.max(0, options.findIndex((o) => o.value === selectedValue)),
79
+ [options, selectedValue],
80
+ );
81
+
82
+ // Scroll to selected value on mount and when selectedValue changes externally
83
+ React.useEffect(() => {
84
+ const el = containerRef.current;
85
+ if (!el) return;
86
+ // Only programmatically scroll when not user-initiated
87
+ if (isUserScrolling.current) return;
88
+ const targetTop = selectedIndex * ITEM_HEIGHT;
89
+ el.scrollTo({ top: targetTop, behavior: 'instant' });
90
+ }, [selectedIndex]);
91
+
92
+ React.useEffect(() => {
93
+ isMounted.current = true;
94
+ return () => {
95
+ isMounted.current = false;
96
+ if (scrollTimer.current) clearTimeout(scrollTimer.current);
97
+ };
98
+ }, []);
99
+
100
+ const handleScroll = React.useCallback(() => {
101
+ isUserScrolling.current = true;
102
+ if (scrollTimer.current) clearTimeout(scrollTimer.current);
103
+
104
+ scrollTimer.current = setTimeout(() => {
105
+ if (!isMounted.current) return;
106
+ const el = containerRef.current;
107
+ if (!el) return;
108
+
109
+ const scrollTop = el.scrollTop;
110
+ const closestIndex = Math.round(scrollTop / ITEM_HEIGHT);
111
+ const clampedIndex = Math.max(0, Math.min(closestIndex, options.length - 1));
112
+
113
+ // Snap to the closest item
114
+ el.scrollTo({ top: clampedIndex * ITEM_HEIGHT, behavior: 'smooth' });
115
+
116
+ const newValue = options[clampedIndex]?.value;
117
+ if (newValue && newValue !== selectedValue) {
118
+ onChange(newValue);
119
+ }
120
+
121
+ // Reset flag after snap completes
122
+ setTimeout(() => {
123
+ if (isMounted.current) isUserScrolling.current = false;
124
+ }, 150);
125
+ }, SCROLL_DEBOUNCE);
126
+ }, [options, selectedValue, onChange]);
127
+
128
+ const handleItemClick = React.useCallback(
129
+ (index: number) => {
130
+ const el = containerRef.current;
131
+ if (!el) return;
132
+ isUserScrolling.current = true;
133
+ el.scrollTo({ top: index * ITEM_HEIGHT, behavior: 'smooth' });
134
+ const newValue = options[index]?.value;
135
+ if (newValue) onChange(newValue);
136
+ setTimeout(() => {
137
+ if (isMounted.current) isUserScrolling.current = false;
138
+ }, 300);
139
+ },
140
+ [options, onChange],
141
+ );
142
+
143
+ return (
144
+ <div
145
+ ref={containerRef}
146
+ onScroll={handleScroll}
147
+ className="flex-1 overflow-y-auto overscroll-contain scrollbar-none"
148
+ style={{
149
+ height: CONTAINER_HEIGHT,
150
+ scrollSnapType: 'y mandatory',
151
+ WebkitOverflowScrolling: 'touch',
152
+ scrollbarWidth: 'none',
153
+ msOverflowStyle: 'none',
154
+ }}
155
+ >
156
+ {/* Top padding so first item can center */}
157
+ <div style={{ height: PADDING_HEIGHT }} aria-hidden />
158
+
159
+ {options.map((option, i) => {
160
+ const distance = Math.abs(i - selectedIndex);
161
+ const isSelected = i === selectedIndex;
162
+
163
+ // Opacity gradient: selected=1, +-1=0.4, +-2=0.2, beyond=0
164
+ let opacity = 0;
165
+ if (isSelected) opacity = 1;
166
+ else if (distance === 1) opacity = 0.4;
167
+ else if (distance === 2) opacity = 0.2;
168
+
169
+ return (
170
+ <div
171
+ key={option.value}
172
+ onClick={() => handleItemClick(i)}
173
+ className={cn(
174
+ 'flex items-center justify-center cursor-pointer select-none transition-all duration-150',
175
+ isSelected
176
+ ? 'bg-accent text-text-highlight rounded-[6px] font-normal'
177
+ : 'text-text-dim',
178
+ )}
179
+ style={{
180
+ height: ITEM_HEIGHT,
181
+ scrollSnapAlign: 'center',
182
+ opacity: isSelected ? 1 : opacity,
183
+ }}
184
+ >
185
+ <span className="text-[17px] tracking-[-0.17px]">{option.label}</span>
186
+ </div>
187
+ );
188
+ })}
189
+
190
+ {/* Bottom padding so last item can center */}
191
+ <div style={{ height: PADDING_HEIGHT }} aria-hidden />
192
+ </div>
193
+ );
194
+ }
195
+
196
+ /* -------------------------------------------------------------------------- */
197
+ /* ScrollPicker */
198
+ /* -------------------------------------------------------------------------- */
199
+
200
+ function ScrollPicker({ open, onClose, title, columns, value, onValueChange }: ScrollPickerProps) {
201
+ // Close on Escape
202
+ React.useEffect(() => {
203
+ if (!open) return;
204
+ const handler = (e: KeyboardEvent) => {
205
+ if (e.key === 'Escape') onClose();
206
+ };
207
+ document.addEventListener('keydown', handler);
208
+ return () => document.removeEventListener('keydown', handler);
209
+ }, [open, onClose]);
210
+
211
+ // Prevent body scroll when open
212
+ React.useEffect(() => {
213
+ if (!open) return;
214
+ const prev = document.body.style.overflow;
215
+ document.body.style.overflow = 'hidden';
216
+ return () => {
217
+ document.body.style.overflow = prev;
218
+ };
219
+ }, [open]);
220
+
221
+ const handleColumnChange = React.useCallback(
222
+ (columnIndex: number, newVal: string) => {
223
+ const next = [...value];
224
+ next[columnIndex] = newVal;
225
+ onValueChange(next);
226
+ },
227
+ [value, onValueChange],
228
+ );
229
+
230
+ if (!open) return null;
231
+
232
+ return (
233
+ <div className="fixed inset-0 z-50 flex items-end justify-center">
234
+ {/* Overlay */}
235
+ <div className="absolute inset-0 bg-overlay" onClick={onClose} />
236
+
237
+ {/* Panel */}
238
+ <div className="relative z-10 w-full max-w-[393px] bg-bg rounded-t-[6px] shadow-[0px_-4px_12px_0px_rgba(0,0,0,0.12)] pt-3">
239
+ {/* Title */}
240
+ <div className="px-4 py-3">
241
+ <h2 className="text-[17px] tracking-[-0.17px] font-normal text-text text-center">
242
+ {title}
243
+ </h2>
244
+ </div>
245
+
246
+ {/* Columns */}
247
+ <div className="relative flex items-center px-3" style={{ height: CONTAINER_HEIGHT }}>
248
+ {columns.map((col, colIndex) => {
249
+ // Resolve separator: check current column first, then previous column
250
+ const sep = colIndex > 0
251
+ ? (col.separator ?? columns[colIndex - 1]?.separator)
252
+ : undefined;
253
+
254
+ return (
255
+ <React.Fragment key={colIndex}>
256
+ {/* Separator between columns */}
257
+ {sep && (
258
+ <div
259
+ className="flex items-center justify-center shrink-0 px-1"
260
+ style={{ height: CONTAINER_HEIGHT }}
261
+ >
262
+ <span className="text-[17px] tracking-[-0.17px] font-normal text-text">
263
+ {sep}
264
+ </span>
265
+ </div>
266
+ )}
267
+ <Column
268
+ options={col.options}
269
+ selectedValue={value[colIndex] ?? col.options[0]?.value ?? ''}
270
+ onChange={(v) => handleColumnChange(colIndex, v)}
271
+ />
272
+ </React.Fragment>
273
+ );
274
+ })}
275
+ </div>
276
+
277
+ {/* Done button */}
278
+ <div className="px-3 pt-3">
279
+ <button
280
+ type="button"
281
+ onClick={onClose}
282
+ className="w-full h-12 rounded-[6px] bg-surface text-text text-[17px] tracking-[-0.17px] font-normal cursor-pointer transition-colors hover:bg-surface-light"
283
+ >
284
+ Done
285
+ </button>
286
+ </div>
287
+
288
+ {/* Home indicator */}
289
+ <div className="flex items-center justify-center h-[42px]">
290
+ <div className="w-[139px] h-[5px] rounded-full bg-text" />
291
+ </div>
292
+ </div>
293
+ </div>
294
+ );
295
+ }
296
+
297
+ /* -------------------------------------------------------------------------- */
298
+ /* DatePicker */
299
+ /* -------------------------------------------------------------------------- */
300
+
301
+ const MONTHS = [
302
+ 'January', 'February', 'March', 'April', 'May', 'June',
303
+ 'July', 'August', 'September', 'October', 'November', 'December',
304
+ ];
305
+
306
+ function DatePicker({
307
+ open,
308
+ onClose,
309
+ title = 'Select Date',
310
+ value,
311
+ onValueChange,
312
+ minYear = 1900,
313
+ maxYear = 2100,
314
+ }: DatePickerProps) {
315
+ const dayOptions = React.useMemo(
316
+ () =>
317
+ Array.from({ length: 31 }, (_, i) => ({
318
+ value: String(i + 1),
319
+ label: String(i + 1),
320
+ })),
321
+ [],
322
+ );
323
+
324
+ const monthOptions = React.useMemo(
325
+ () =>
326
+ MONTHS.map((m, i) => ({
327
+ value: String(i + 1),
328
+ label: m,
329
+ })),
330
+ [],
331
+ );
332
+
333
+ const yearOptions = React.useMemo(
334
+ () =>
335
+ Array.from({ length: maxYear - minYear + 1 }, (_, i) => ({
336
+ value: String(minYear + i),
337
+ label: String(minYear + i),
338
+ })),
339
+ [minYear, maxYear],
340
+ );
341
+
342
+ const columns: ScrollColumn[] = React.useMemo(
343
+ () => [
344
+ { options: dayOptions },
345
+ { options: monthOptions },
346
+ { options: yearOptions },
347
+ ],
348
+ [dayOptions, monthOptions, yearOptions],
349
+ );
350
+
351
+ const pickerValue = React.useMemo(
352
+ () => [String(value.day), String(value.month), String(value.year)],
353
+ [value.day, value.month, value.year],
354
+ );
355
+
356
+ const handleChange = React.useCallback(
357
+ (v: string[]) => {
358
+ onValueChange({
359
+ day: parseInt(v[0], 10) || 1,
360
+ month: parseInt(v[1], 10) || 1,
361
+ year: parseInt(v[2], 10) || 2024,
362
+ });
363
+ },
364
+ [onValueChange],
365
+ );
366
+
367
+ return (
368
+ <ScrollPicker
369
+ open={open}
370
+ onClose={onClose}
371
+ title={title}
372
+ columns={columns}
373
+ value={pickerValue}
374
+ onValueChange={handleChange}
375
+ />
376
+ );
377
+ }
378
+
379
+ /* -------------------------------------------------------------------------- */
380
+ /* TimePicker */
381
+ /* -------------------------------------------------------------------------- */
382
+
383
+ function TimePicker({
384
+ open,
385
+ onClose,
386
+ title = 'Select Time',
387
+ value,
388
+ onValueChange,
389
+ format = '24h',
390
+ }: TimePickerProps) {
391
+ const is12h = format === '12h';
392
+
393
+ const hourOptions = React.useMemo(
394
+ () => {
395
+ const max = is12h ? 12 : 23;
396
+ const min = is12h ? 1 : 0;
397
+ return Array.from({ length: max - min + 1 }, (_, i) => ({
398
+ value: String(min + i),
399
+ label: String(min + i).padStart(2, '0'),
400
+ }));
401
+ },
402
+ [is12h],
403
+ );
404
+
405
+ const minuteOptions = React.useMemo(
406
+ () =>
407
+ Array.from({ length: 60 }, (_, i) => ({
408
+ value: String(i),
409
+ label: String(i).padStart(2, '0'),
410
+ })),
411
+ [],
412
+ );
413
+
414
+ const periodOptions = React.useMemo(
415
+ () => [
416
+ { value: 'AM', label: 'AM' },
417
+ { value: 'PM', label: 'PM' },
418
+ ],
419
+ [],
420
+ );
421
+
422
+ const columns: ScrollColumn[] = React.useMemo(() => {
423
+ const cols: ScrollColumn[] = [
424
+ { options: hourOptions },
425
+ { options: minuteOptions, separator: ':' },
426
+ ];
427
+ if (is12h) {
428
+ cols.push({ options: periodOptions });
429
+ }
430
+ return cols;
431
+ }, [hourOptions, minuteOptions, periodOptions, is12h]);
432
+
433
+ const pickerValue = React.useMemo(() => {
434
+ const vals = [String(value.hour), String(value.minute)];
435
+ if (is12h) vals.push(value.period ?? 'AM');
436
+ return vals;
437
+ }, [value.hour, value.minute, value.period, is12h]);
438
+
439
+ const handleChange = React.useCallback(
440
+ (v: string[]) => {
441
+ const result: { hour: number; minute: number; period?: 'AM' | 'PM' } = {
442
+ hour: parseInt(v[0], 10) || 0,
443
+ minute: parseInt(v[1], 10) || 0,
444
+ };
445
+ if (is12h) {
446
+ result.period = (v[2] as 'AM' | 'PM') ?? 'AM';
447
+ }
448
+ onValueChange(result);
449
+ },
450
+ [is12h, onValueChange],
451
+ );
452
+
453
+ return (
454
+ <ScrollPicker
455
+ open={open}
456
+ onClose={onClose}
457
+ title={title}
458
+ columns={columns}
459
+ value={pickerValue}
460
+ onValueChange={handleChange}
461
+ />
462
+ );
463
+ }
464
+
465
+ /* -------------------------------------------------------------------------- */
466
+ /* SelectionPicker */
467
+ /* -------------------------------------------------------------------------- */
468
+
469
+ function SelectionPicker({
470
+ open,
471
+ onClose,
472
+ title = 'Select',
473
+ options,
474
+ value,
475
+ onValueChange,
476
+ }: SelectionPickerProps) {
477
+ const columns: ScrollColumn[] = React.useMemo(
478
+ () => [{ options }],
479
+ [options],
480
+ );
481
+
482
+ const pickerValue = React.useMemo(() => [value], [value]);
483
+
484
+ const handleChange = React.useCallback(
485
+ (v: string[]) => {
486
+ onValueChange(v[0] ?? '');
487
+ },
488
+ [onValueChange],
489
+ );
490
+
491
+ return (
492
+ <ScrollPicker
493
+ open={open}
494
+ onClose={onClose}
495
+ title={title}
496
+ columns={columns}
497
+ value={pickerValue}
498
+ onValueChange={handleChange}
499
+ />
500
+ );
501
+ }
502
+
503
+ /* -------------------------------------------------------------------------- */
504
+ /* Exports */
505
+ /* -------------------------------------------------------------------------- */
506
+
507
+ export { ScrollPicker, DatePicker, TimePicker, SelectionPicker };
508
+ export type { ScrollPickerProps, ScrollColumn, DatePickerProps, TimePickerProps, SelectionPickerProps };
@@ -0,0 +1,28 @@
1
+ import * as React from 'react';
2
+ import { cn } from '../utils/cn';
3
+ import { IcGuideSearch } from '../icons/svg-icons';
4
+
5
+ interface SearchBarProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> {
6
+ value: string;
7
+ onChange: React.ChangeEventHandler<HTMLInputElement>;
8
+ }
9
+
10
+ const SearchBar = React.forwardRef<HTMLInputElement, SearchBarProps>(
11
+ ({ className, placeholder = 'Search...', ...props }, ref) => (
12
+ <div className={cn('relative', className)}>
13
+ <IcGuideSearch className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-text-dim pointer-events-none" />
14
+ <input
15
+ ref={ref}
16
+ type="search"
17
+ placeholder={placeholder}
18
+ className="h-9 w-full bg-input-bg text-text rounded-[6px] pl-11 pr-4 text-[17px] tracking-[-0.17px] outline-none placeholder:text-text-dim transition-colors"
19
+ {...props}
20
+ />
21
+ </div>
22
+ ),
23
+ );
24
+
25
+ SearchBar.displayName = 'SearchBar';
26
+
27
+ export { SearchBar };
28
+ export type { SearchBarProps };
@@ -0,0 +1,20 @@
1
+ import { cn } from '../utils/cn';
2
+ import type { ReactNode } from 'react';
3
+
4
+ interface SectionHeaderProps {
5
+ title: string;
6
+ action?: ReactNode;
7
+ className?: string;
8
+ }
9
+
10
+ function SectionHeader({ title, action, className }: SectionHeaderProps) {
11
+ return (
12
+ <div className={cn('flex items-center justify-between mb-3 mt-6', className)}>
13
+ <span className="text-[20px] tracking-[-0.6px] font-normal text-text">{title}</span>
14
+ {action}
15
+ </div>
16
+ );
17
+ }
18
+
19
+ export { SectionHeader };
20
+ export type { SectionHeaderProps };
@@ -0,0 +1,50 @@
1
+ import { cn } from '../utils/cn';
2
+
3
+ interface SegmentedControlOption {
4
+ value: string;
5
+ label: string;
6
+ }
7
+
8
+ interface SegmentedControlProps {
9
+ options: SegmentedControlOption[];
10
+ value: string;
11
+ onValueChange: (value: string) => void;
12
+ size?: 'default' | 'small' | 'xsmall';
13
+ className?: string;
14
+ }
15
+
16
+ function SegmentedControl({ options, value, onValueChange, size = 'default', className }: SegmentedControlProps) {
17
+ return (
18
+ <div
19
+ className={cn(
20
+ 'inline-flex rounded-[6px] bg-surface-lighter p-0.5',
21
+ size === 'default' && 'h-12',
22
+ size === 'small' && 'h-9',
23
+ size === 'xsmall' && 'h-6',
24
+ className,
25
+ )}
26
+ >
27
+ {options.map((opt) => (
28
+ <button
29
+ key={opt.value}
30
+ type="button"
31
+ onClick={() => onValueChange(opt.value)}
32
+ className={cn(
33
+ 'flex-1 px-4 font-normal transition-all cursor-pointer rounded-[4px]',
34
+ size === 'default' && 'text-[17px] tracking-[-0.17px]',
35
+ size === 'small' && 'text-[15px] tracking-[-0.15px] px-3',
36
+ size === 'xsmall' && 'text-[13px] tracking-[-0.13px] px-2',
37
+ value === opt.value
38
+ ? 'bg-surface text-text shadow-[0_1px_3px_rgba(0,0,0,0.12),0_1px_2px_rgba(0,0,0,0.06)]'
39
+ : 'text-text-dim hover:text-text',
40
+ )}
41
+ >
42
+ {opt.label}
43
+ </button>
44
+ ))}
45
+ </div>
46
+ );
47
+ }
48
+
49
+ export { SegmentedControl };
50
+ export type { SegmentedControlProps, SegmentedControlOption };
@@ -0,0 +1,37 @@
1
+ import * as React from 'react';
2
+ import { cn } from '../utils/cn';
3
+
4
+ interface SelectOption {
5
+ value: string;
6
+ label: string;
7
+ }
8
+
9
+ interface SelectProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, 'onChange'> {
10
+ options: SelectOption[];
11
+ onValueChange?: (value: string) => void;
12
+ }
13
+
14
+ const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
15
+ ({ className, options, onValueChange, ...props }, ref) => (
16
+ <select
17
+ ref={ref}
18
+ className={cn(
19
+ 'h-9 w-full bg-input-bg text-text rounded-[6px] pl-4 pr-10 text-[17px] tracking-[-0.17px] outline-none transition-colors cursor-pointer',
20
+ className,
21
+ )}
22
+ onChange={(e) => onValueChange?.(e.target.value)}
23
+ {...props}
24
+ >
25
+ {options.map((o) => (
26
+ <option key={o.value} value={o.value}>
27
+ {o.label}
28
+ </option>
29
+ ))}
30
+ </select>
31
+ ),
32
+ );
33
+
34
+ Select.displayName = 'Select';
35
+
36
+ export { Select };
37
+ export type { SelectProps, SelectOption };
@@ -0,0 +1,22 @@
1
+ import type { ReactNode } from 'react';
2
+ import { cn } from '../utils/cn';
3
+
4
+ interface SettingsGroupProps {
5
+ label: string;
6
+ children: ReactNode;
7
+ className?: string;
8
+ }
9
+
10
+ function SettingsGroup({ label, children, className }: SettingsGroupProps) {
11
+ return (
12
+ <div className={cn('rounded-[6px] overflow-hidden', className)}>
13
+ <div className="pb-1.5">
14
+ <span className="text-[13px] tracking-[-0.13px] text-text-dim">{label}</span>
15
+ </div>
16
+ <div className="divide-y divide-border">{children}</div>
17
+ </div>
18
+ );
19
+ }
20
+
21
+ export { SettingsGroup };
22
+ export type { SettingsGroupProps };
@@ -0,0 +1,36 @@
1
+ import { cva, type VariantProps } from 'class-variance-authority';
2
+ import { cn } from '../utils/cn';
3
+
4
+ const skeletonVariants = cva('bg-surface-lighter animate-pulse', {
5
+ variants: {
6
+ rounded: {
7
+ default: 'rounded-[6px]',
8
+ full: 'rounded-full',
9
+ none: 'rounded-none',
10
+ },
11
+ },
12
+ defaultVariants: {
13
+ rounded: 'default',
14
+ },
15
+ });
16
+
17
+ interface SkeletonProps extends VariantProps<typeof skeletonVariants> {
18
+ width?: string | number;
19
+ height?: string | number;
20
+ className?: string;
21
+ }
22
+
23
+ function Skeleton({ width, height, rounded, className }: SkeletonProps) {
24
+ return (
25
+ <div
26
+ className={cn(skeletonVariants({ rounded, className }))}
27
+ style={{
28
+ width: typeof width === 'number' ? `${width}px` : width,
29
+ height: typeof height === 'number' ? `${height}px` : (height ?? '16px'),
30
+ }}
31
+ />
32
+ );
33
+ }
34
+
35
+ export { Skeleton, skeletonVariants };
36
+ export type { SkeletonProps };