@zyncat/ui 0.10.0 → 0.12.0

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 (597) hide show
  1. package/README.md +135 -40
  2. package/dist/alert.css +126 -121
  3. package/dist/alert.js +12 -14
  4. package/dist/alert.js.map +1 -1
  5. package/dist/avatar-group.js.map +1 -1
  6. package/dist/avatar.css +179 -174
  7. package/dist/avatar.js.map +1 -1
  8. package/dist/badge.css +166 -160
  9. package/dist/badge.js +1 -1
  10. package/dist/button.css +272 -246
  11. package/dist/button.js +1 -1
  12. package/dist/checkbox.css +158 -153
  13. package/dist/checkbox.js +2 -2
  14. package/dist/{chunk-UXONUUPI.js → chunk-227ZW4V7.js} +40 -32
  15. package/dist/chunk-227ZW4V7.js.map +1 -0
  16. package/dist/{chunk-2ERBBFZS.js → chunk-3MPF7FZV.js} +2 -2
  17. package/dist/chunk-3MPF7FZV.js.map +1 -0
  18. package/dist/{chunk-OMHQ4U4J.js → chunk-43M6GQ4Q.js} +86 -79
  19. package/dist/chunk-43M6GQ4Q.js.map +1 -0
  20. package/dist/{chunk-7SZCJ7WI.js → chunk-45R4Z5XN.js} +3 -3
  21. package/dist/chunk-45R4Z5XN.js.map +1 -0
  22. package/dist/{chunk-I4XQ4PV2.js → chunk-4BSHB7R3.js} +9 -7
  23. package/dist/chunk-4BSHB7R3.js.map +1 -0
  24. package/dist/{chunk-YGGCQNNU.js → chunk-4C5RZXBT.js} +33 -34
  25. package/dist/chunk-4C5RZXBT.js.map +1 -0
  26. package/dist/{chunk-2QWJ6FAX.js → chunk-5PZ43DCG.js} +31 -15
  27. package/dist/chunk-5PZ43DCG.js.map +1 -0
  28. package/dist/{chunk-S5ZTZANS.js → chunk-7IZJERGA.js} +35 -12
  29. package/dist/chunk-7IZJERGA.js.map +1 -0
  30. package/dist/{chunk-ZCOUPPTI.js → chunk-A5WTZACK.js} +22 -12
  31. package/dist/chunk-A5WTZACK.js.map +1 -0
  32. package/dist/{chunk-64UU4LGU.js → chunk-AADAJL7D.js} +3 -3
  33. package/dist/{chunk-64UU4LGU.js.map → chunk-AADAJL7D.js.map} +1 -1
  34. package/dist/{chunk-FTOAUJL5.js → chunk-CF4QHO4N.js} +21 -11
  35. package/dist/chunk-CF4QHO4N.js.map +1 -0
  36. package/dist/{chunk-WM5J5TDI.js → chunk-CNWTIMIP.js} +13 -17
  37. package/dist/chunk-CNWTIMIP.js.map +1 -0
  38. package/dist/{chunk-356HZMT4.js → chunk-DDRSMHN4.js} +31 -22
  39. package/dist/chunk-DDRSMHN4.js.map +1 -0
  40. package/dist/{chunk-VTJTGVZZ.js → chunk-DMX2F6B4.js} +2 -2
  41. package/dist/chunk-DMX2F6B4.js.map +1 -0
  42. package/dist/{chunk-3SBCBYB7.js → chunk-EAI4POPB.js} +2 -2
  43. package/dist/{chunk-3SBCBYB7.js.map → chunk-EAI4POPB.js.map} +1 -1
  44. package/dist/{chunk-Y7AJQVWJ.js → chunk-EF6RPXU7.js} +17 -15
  45. package/dist/chunk-EF6RPXU7.js.map +1 -0
  46. package/dist/{chunk-K5X2GCXU.js → chunk-FONOS5RN.js} +14 -15
  47. package/dist/chunk-FONOS5RN.js.map +1 -0
  48. package/dist/{chunk-PMECHR3A.js → chunk-FQEHSKEI.js} +2 -2
  49. package/dist/chunk-FQEHSKEI.js.map +1 -0
  50. package/dist/chunk-HDSFWZ7L.js +12 -0
  51. package/dist/chunk-HDSFWZ7L.js.map +1 -0
  52. package/dist/{chunk-2F5PITAO.js → chunk-HY5MPISE.js} +2 -2
  53. package/dist/chunk-HY5MPISE.js.map +1 -0
  54. package/dist/{chunk-QDK66S4G.js → chunk-I45AU6KH.js} +3 -3
  55. package/dist/chunk-I45AU6KH.js.map +1 -0
  56. package/dist/{chunk-YGCVWGUG.js → chunk-IJS7TPGV.js} +153 -46
  57. package/dist/chunk-IJS7TPGV.js.map +1 -0
  58. package/dist/{chunk-62P3KD57.js → chunk-IUQAUBVM.js} +18 -11
  59. package/dist/chunk-IUQAUBVM.js.map +1 -0
  60. package/dist/chunk-JY6A2ZJZ.js +44 -0
  61. package/dist/chunk-JY6A2ZJZ.js.map +1 -0
  62. package/dist/{chunk-XWUWYSCT.js → chunk-M43IOM5C.js} +20 -10
  63. package/dist/chunk-M43IOM5C.js.map +1 -0
  64. package/dist/{chunk-S7B34VGN.js → chunk-OWNMRMPN.js} +3 -3
  65. package/dist/{chunk-S7B34VGN.js.map → chunk-OWNMRMPN.js.map} +1 -1
  66. package/dist/chunk-RFRE4WKX.js +22 -0
  67. package/dist/chunk-RFRE4WKX.js.map +1 -0
  68. package/dist/{chunk-NNXJCLTV.js → chunk-RJFGWJ4W.js} +2 -2
  69. package/dist/chunk-RJFGWJ4W.js.map +1 -0
  70. package/dist/{chunk-NEF5XAHG.js → chunk-TUTXXC3W.js} +4 -4
  71. package/dist/chunk-TUTXXC3W.js.map +1 -0
  72. package/dist/chunk-TVYH4AN7.js +70 -0
  73. package/dist/chunk-TVYH4AN7.js.map +1 -0
  74. package/dist/{chunk-RCONNA7I.js → chunk-VAXCXZ53.js} +34 -22
  75. package/dist/chunk-VAXCXZ53.js.map +1 -0
  76. package/dist/chunk-XNIYSAMJ.js +52 -0
  77. package/dist/chunk-XNIYSAMJ.js.map +1 -0
  78. package/dist/{chunk-CONSWNIV.js → chunk-Y2YA7QRF.js} +6 -6
  79. package/dist/chunk-Y2YA7QRF.js.map +1 -0
  80. package/dist/cli.js +1809 -0
  81. package/dist/collapse.css +70 -61
  82. package/dist/collapse.js +2 -2
  83. package/dist/confetti.css +45 -0
  84. package/dist/confetti.js +540 -0
  85. package/dist/confetti.js.map +1 -0
  86. package/dist/count-badge.js +3 -3
  87. package/dist/count-badge.js.map +1 -1
  88. package/dist/date-field.js +24 -19
  89. package/dist/date-field.js.map +1 -1
  90. package/dist/date-picker.css +563 -559
  91. package/dist/date-range-field.js +58 -41
  92. package/dist/date-range-field.js.map +1 -1
  93. package/dist/datetime-field.js +24 -19
  94. package/dist/datetime-field.js.map +1 -1
  95. package/dist/dialog.css +176 -172
  96. package/dist/dialog.js +30 -19
  97. package/dist/dialog.js.map +1 -1
  98. package/dist/digit-strip.css +65 -0
  99. package/dist/dropdown.css +65 -0
  100. package/dist/dropdown.js +350 -0
  101. package/dist/dropdown.js.map +1 -0
  102. package/dist/emoji-picker.js +713 -0
  103. package/dist/emoji-picker.js.map +1 -0
  104. package/dist/facebook-feed.css +880 -0
  105. package/dist/facebook-feed.js +697 -0
  106. package/dist/facebook-feed.js.map +1 -0
  107. package/dist/flow-field.css +49 -0
  108. package/dist/flow-field.js +269 -0
  109. package/dist/flow-field.js.map +1 -0
  110. package/dist/glide.js +3 -3
  111. package/dist/icon.css +34 -30
  112. package/dist/input.css +296 -318
  113. package/dist/instagram-feed.css +378 -0
  114. package/dist/instagram-feed.js +272 -0
  115. package/dist/instagram-feed.js.map +1 -0
  116. package/dist/lens.css +119 -0
  117. package/dist/lens.js +307 -0
  118. package/dist/lens.js.map +1 -0
  119. package/dist/mcp.js +379 -184
  120. package/dist/menu-surface.css +127 -0
  121. package/dist/modal.css +11 -7
  122. package/dist/modal.js +24 -17
  123. package/dist/modal.js.map +1 -1
  124. package/dist/morphing-text.css +84 -0
  125. package/dist/morphing-text.js +256 -0
  126. package/dist/morphing-text.js.map +1 -0
  127. package/dist/motion-devtools.css +237 -233
  128. package/dist/motion-devtools.js +7 -6
  129. package/dist/motion-devtools.js.map +1 -1
  130. package/dist/motion-tokens.js +1 -1
  131. package/dist/multi-select.js +20 -17
  132. package/dist/multi-select.js.map +1 -1
  133. package/dist/number-field.js +11 -7
  134. package/dist/number-field.js.map +1 -1
  135. package/dist/odometer.css +58 -59
  136. package/dist/odometer.js +109 -0
  137. package/dist/odometer.js.map +1 -0
  138. package/dist/otp-field.js.map +1 -1
  139. package/dist/overlay.css +24 -20
  140. package/dist/pagination.css +42 -38
  141. package/dist/pagination.js +6 -12
  142. package/dist/pagination.js.map +1 -1
  143. package/dist/popover.css +69 -65
  144. package/dist/popover.js +12 -10
  145. package/dist/radio-group.css +275 -276
  146. package/dist/radio-group.js +70 -95
  147. package/dist/radio-group.js.map +1 -1
  148. package/dist/select.css +291 -386
  149. package/dist/select.js +18 -15
  150. package/dist/select.js.map +1 -1
  151. package/dist/sheet.css +47 -23
  152. package/dist/sheet.js +11 -10
  153. package/dist/status-badge.js +3 -3
  154. package/dist/status-badge.js.map +1 -1
  155. package/dist/styles.css +221 -0
  156. package/dist/support-rail.css +421 -0
  157. package/dist/support-rail.js +243 -0
  158. package/dist/support-rail.js.map +1 -0
  159. package/dist/table.css +333 -323
  160. package/dist/table.js +32 -21
  161. package/dist/table.js.map +1 -1
  162. package/dist/tabs.css +163 -156
  163. package/dist/tabs.js +26 -20
  164. package/dist/tabs.js.map +1 -1
  165. package/dist/tag.css +209 -231
  166. package/dist/tag.js +11 -10
  167. package/dist/tag.js.map +1 -1
  168. package/dist/text-field.js +7 -67
  169. package/dist/text-field.js.map +1 -1
  170. package/dist/textarea.css +205 -211
  171. package/dist/textarea.js +12 -12
  172. package/dist/textarea.js.map +1 -1
  173. package/dist/theme.js +69 -0
  174. package/dist/theme.js.map +1 -0
  175. package/dist/tiktok.css +662 -0
  176. package/dist/tiktok.js +494 -0
  177. package/dist/tiktok.js.map +1 -0
  178. package/dist/time-field.js +6 -6
  179. package/dist/time-field.js.map +1 -1
  180. package/dist/toast.css +237 -233
  181. package/dist/toast.js +43 -47
  182. package/dist/toast.js.map +1 -1
  183. package/dist/toggle-tag.js +1 -1
  184. package/dist/toggle-tag.js.map +1 -1
  185. package/dist/toggle.css +139 -135
  186. package/dist/toggle.js.map +1 -1
  187. package/dist/tooltip.css +79 -78
  188. package/dist/tooltip.js +50 -60
  189. package/dist/tooltip.js.map +1 -1
  190. package/dist/trigger.css +13 -0
  191. package/dist/{alert.d.ts → types/components/composites/alert/Alert.d.ts} +13 -15
  192. package/dist/{date-field.d.ts → types/components/composites/date-picker/DateField.d.ts} +4 -10
  193. package/dist/types/components/composites/date-picker/DateRangeField.d.ts +21 -0
  194. package/dist/{datetime-field.d.ts → types/components/composites/date-picker/DateTimeField.d.ts} +4 -10
  195. package/dist/{time-field.d.ts → types/components/composites/date-picker/TimeField.d.ts} +5 -11
  196. package/dist/types/components/composites/date-picker/calendar-panel.d.ts +16 -0
  197. package/dist/types/components/composites/date-picker/date-utils.d.ts +12 -0
  198. package/dist/types/components/composites/date-picker/field-shell.d.ts +46 -0
  199. package/dist/types/components/composites/date-picker/range-panel.d.ts +24 -0
  200. package/dist/types/components/composites/date-picker/time-core.d.ts +14 -0
  201. package/dist/types/components/composites/date-picker/use-day-focus.d.ts +2 -0
  202. package/dist/{dialog.d.ts → types/components/composites/dialog/Dialog.d.ts} +10 -11
  203. package/dist/types/components/composites/dropdown/Dropdown.d.ts +37 -0
  204. package/dist/types/components/composites/dropdown/menu-panel.d.ts +7 -0
  205. package/dist/types/components/composites/dropdown/types.d.ts +71 -0
  206. package/dist/types/components/composites/emoji-picker/EmojiPickerPanel.d.ts +45 -0
  207. package/dist/types/components/composites/emoji-picker/category-icons.d.ts +9 -0
  208. package/dist/types/components/composites/emoji-picker/data.d.ts +33 -0
  209. package/dist/types/components/composites/emoji-picker/dom.d.ts +19 -0
  210. package/dist/types/components/composites/emoji-picker/getEmojiUrl.d.ts +2 -0
  211. package/dist/types/components/composites/emoji-picker/navigation.d.ts +7 -0
  212. package/dist/types/components/composites/emoji-picker/picker.d.ts +20 -0
  213. package/dist/types/components/composites/emoji-picker/react/category-bar.d.ts +6 -0
  214. package/dist/types/components/composites/emoji-picker/react/useEmojiPicker.d.ts +50 -0
  215. package/dist/types/components/composites/emoji-picker/scaffold.d.ts +8 -0
  216. package/dist/types/components/composites/emoji-picker/search.d.ts +1 -0
  217. package/dist/types/components/composites/emoji-picker/types.d.ts +13 -0
  218. package/dist/{modal.d.ts → types/components/composites/modal/Modal.d.ts} +10 -11
  219. package/dist/{pagination.d.ts → types/components/composites/pagination/Pagination.d.ts} +5 -8
  220. package/dist/{popover.d.ts → types/components/composites/popover/Popover.d.ts} +11 -14
  221. package/dist/{multi-select.d.ts → types/components/composites/select/MultiSelect.d.ts} +12 -11
  222. package/dist/{select.d.ts → types/components/composites/select/Select.d.ts} +16 -14
  223. package/dist/types/components/composites/select/core/index.d.ts +4 -0
  224. package/dist/types/components/composites/select/core/menu.d.ts +13 -0
  225. package/dist/types/components/composites/select/core/panel.d.ts +18 -0
  226. package/dist/types/components/composites/select/core/trigger.d.ts +16 -0
  227. package/dist/{types-SGMShK7R.d.ts → types/components/composites/select/core/types.d.ts} +13 -6
  228. package/dist/types/components/composites/select/core/use-listbox.d.ts +42 -0
  229. package/dist/{sheet.d.ts → types/components/composites/sheet/Sheet.d.ts} +10 -11
  230. package/dist/types/components/composites/sheet/use-sheet-drag.d.ts +13 -0
  231. package/dist/{table.d.ts → types/components/composites/table/Table.d.ts} +12 -12
  232. package/dist/{tabs.d.ts → types/components/composites/tabs/Tabs.d.ts} +13 -13
  233. package/dist/types/components/composites/toast/Toast.d.ts +10 -0
  234. package/dist/{toast-store.d.ts → types/components/composites/toast/toast-store.d.ts} +12 -14
  235. package/dist/{tooltip.d.ts → types/components/composites/tooltip/Tooltip.d.ts} +6 -10
  236. package/dist/types/components/composites/tooltip/tooltip-host.d.ts +1 -0
  237. package/dist/types/components/composites/tooltip/tooltip-store.d.ts +29 -0
  238. package/dist/types/components/compound/support-rail/SupportRail.d.ts +41 -0
  239. package/dist/types/components/dev/MotionDevtools.d.ts +24 -0
  240. package/dist/types/components/dev/slowmo-engine.d.ts +27 -0
  241. package/dist/types/components/expressive/confetti/Confetti.d.ts +43 -0
  242. package/dist/types/components/expressive/facebook-feed/FacebookFeed.d.ts +73 -0
  243. package/dist/types/components/expressive/facebook-feed/chrome.d.ts +30 -0
  244. package/dist/types/components/expressive/facebook-feed/icons.d.ts +21 -0
  245. package/dist/types/components/expressive/facebook-feed/post.d.ts +25 -0
  246. package/dist/types/components/expressive/facebook-feed/reel.d.ts +26 -0
  247. package/dist/types/components/expressive/facebook-feed/story.d.ts +20 -0
  248. package/dist/types/components/expressive/flow-field/FlowField.d.ts +23 -0
  249. package/dist/types/components/expressive/instagram-feed/InstagramFeed.d.ts +59 -0
  250. package/dist/types/components/expressive/lens/Lens.d.ts +23 -0
  251. package/dist/types/components/expressive/morphing-text/MorphingText.d.ts +21 -0
  252. package/dist/types/components/expressive/odometer/Odometer.d.ts +21 -0
  253. package/dist/types/components/expressive/tiktok/TikTok.d.ts +85 -0
  254. package/dist/types/components/expressive/tiktok/glyphs.d.ts +40 -0
  255. package/dist/types/components/expressive/typing-lines/TypingLines.d.ts +25 -0
  256. package/dist/types/components/expressive/weight-field/WeightField.d.ts +19 -0
  257. package/dist/types/components/expressive/youtube/YouTube.d.ts +73 -0
  258. package/dist/types/components/expressive/youtube/format.d.ts +2 -0
  259. package/dist/types/components/expressive/youtube/glyphs.d.ts +16 -0
  260. package/dist/types/components/expressive/youtube/media.d.ts +8 -0
  261. package/dist/types/components/expressive/youtube/post.d.ts +19 -0
  262. package/dist/types/components/expressive/youtube/short.d.ts +18 -0
  263. package/dist/types/components/expressive/youtube/video.d.ts +14 -0
  264. package/dist/types/components/internal/collection/collection.d.ts +19 -0
  265. package/dist/types/components/internal/glass/glint.d.ts +1 -0
  266. package/dist/types/components/internal/hooks/use-controllable.d.ts +1 -0
  267. package/dist/types/components/internal/hooks/use-media-query.d.ts +1 -0
  268. package/dist/types/components/internal/hooks/use-scroll-edges.d.ts +10 -0
  269. package/dist/types/components/internal/hooks/use-typeahead.d.ts +5 -0
  270. package/dist/types/components/internal/icon/Icon.d.ts +33 -0
  271. package/dist/types/components/internal/icon/IconSlot.d.ts +7 -0
  272. package/dist/types/components/internal/menu/menu-row.d.ts +11 -0
  273. package/dist/types/components/internal/overlay/focus.d.ts +8 -0
  274. package/dist/types/components/internal/overlay/layer.d.ts +38 -0
  275. package/dist/types/components/internal/overlay/modal.d.ts +18 -0
  276. package/dist/types/components/internal/overlay/position.d.ts +14 -0
  277. package/dist/types/components/internal/support/types.d.ts +15 -0
  278. package/dist/types/components/internal/utils/activation.d.ts +23 -0
  279. package/dist/types/components/internal/utils/cx.d.ts +1 -0
  280. package/dist/types/components/internal/utils/token-px.d.ts +1 -0
  281. package/dist/{avatar.d.ts → types/components/primitives/avatar/Avatar.d.ts} +10 -12
  282. package/dist/{avatar-group.d.ts → types/components/primitives/avatar/AvatarGroup.d.ts} +7 -9
  283. package/dist/{badge.d.ts → types/components/primitives/badge/Badge.d.ts} +8 -10
  284. package/dist/types/components/primitives/badge/CountBadge.d.ts +8 -0
  285. package/dist/types/components/primitives/badge/StatusBadge.d.ts +15 -0
  286. package/dist/types/components/primitives/badge/digit-strip.d.ts +5 -0
  287. package/dist/{button.d.ts → types/components/primitives/button/Button.d.ts} +6 -8
  288. package/dist/{checkbox.d.ts → types/components/primitives/checkbox/Checkbox.d.ts} +6 -8
  289. package/dist/types/components/primitives/checkbox/check-glyph.d.ts +6 -0
  290. package/dist/{collapse.d.ts → types/components/primitives/collapse/Collapse.d.ts} +12 -13
  291. package/dist/types/components/primitives/collapse/collapse.typecheck.d.ts +2 -0
  292. package/dist/{number-field.d.ts → types/components/primitives/input/NumberField.d.ts} +7 -9
  293. package/dist/{otp-field.d.ts → types/components/primitives/input/OtpField.d.ts} +6 -8
  294. package/dist/{text-field.d.ts → types/components/primitives/input/TextField.d.ts} +7 -9
  295. package/dist/types/components/primitives/input/field-chrome.d.ts +45 -0
  296. package/dist/{radio-group.d.ts → types/components/primitives/radio-group/RadioGroup.d.ts} +8 -10
  297. package/dist/{tag.d.ts → types/components/primitives/tag/Tag.d.ts} +9 -12
  298. package/dist/{toggle-tag.d.ts → types/components/primitives/tag/ToggleTag.d.ts} +7 -8
  299. package/dist/{textarea.d.ts → types/components/primitives/textarea/Textarea.d.ts} +7 -9
  300. package/dist/{toggle.d.ts → types/components/primitives/toggle/Toggle.d.ts} +6 -8
  301. package/dist/{dom-props-C0jrllBw.d.ts → types/dom-props.d.ts} +1 -3
  302. package/dist/types/engine/animate.d.ts +30 -0
  303. package/dist/types/engine/drag.d.ts +17 -0
  304. package/dist/types/engine/ease.d.ts +15 -0
  305. package/dist/types/engine/flip.d.ts +18 -0
  306. package/dist/types/engine/index.d.ts +4 -0
  307. package/dist/types/engine/loop.d.ts +9 -0
  308. package/dist/types/motion/element.d.ts +17 -0
  309. package/dist/types/motion/flip.d.ts +4 -0
  310. package/dist/types/motion/glide.d.ts +11 -0
  311. package/dist/types/motion/motion-timing.d.ts +16 -0
  312. package/dist/types/motion/presence-context.d.ts +11 -0
  313. package/dist/types/motion/presence.d.ts +12 -0
  314. package/dist/types/motion/presets.d.ts +6 -0
  315. package/dist/{timing-7JA_zQHP.d.ts → types/motion/timing.d.ts} +9 -9
  316. package/dist/types/motion/use-motion.d.ts +17 -0
  317. package/dist/types/tokens/component-styles.generated.d.ts +262 -0
  318. package/dist/{motion-scale-Canq4stZ.d.ts → types/tokens/motion-scale.d.ts} +4 -4
  319. package/dist/{motion-tokens.d.ts → types/tokens/motion-tokens.d.ts} +9 -9
  320. package/dist/types/tokens/theme-tokens.generated.d.ts +1249 -0
  321. package/dist/types/tokens/theme.d.ts +12 -0
  322. package/dist/typing-lines.css +92 -0
  323. package/dist/typing-lines.js +139 -0
  324. package/dist/typing-lines.js.map +1 -0
  325. package/dist/weight-field.css +84 -0
  326. package/dist/weight-field.js +17 -0
  327. package/dist/weight-field.js.map +1 -0
  328. package/dist/youtube.css +611 -0
  329. package/dist/youtube.js +814 -0
  330. package/dist/youtube.js.map +1 -0
  331. package/package.json +155 -49
  332. package/skills/zyncat-ui/SKILL.md +95 -0
  333. package/skills/zyncat-ui/references/components.md +85 -0
  334. package/skills/zyncat-ui/references/recipes.md +171 -0
  335. package/skills/zyncat-ui/references/theming.md +83 -0
  336. package/src/components/composites/alert/Alert.tsx +13 -11
  337. package/src/components/composites/alert/Alert.usage.md +15 -0
  338. package/src/components/composites/alert/alert.css +126 -121
  339. package/src/components/composites/date-picker/DateField.tsx +7 -2
  340. package/src/components/composites/date-picker/DateField.usage.md +10 -0
  341. package/src/components/composites/date-picker/DateRangeField.tsx +18 -16
  342. package/src/components/composites/date-picker/DateRangeField.usage.md +10 -0
  343. package/src/components/composites/date-picker/DateTimeField.tsx +10 -5
  344. package/src/components/composites/date-picker/DateTimeField.usage.md +12 -0
  345. package/src/components/composites/date-picker/TimeField.tsx +3 -1
  346. package/src/components/composites/date-picker/TimeField.usage.md +12 -0
  347. package/src/components/composites/date-picker/calendar-panel.tsx +15 -10
  348. package/src/components/composites/date-picker/date-picker.css +563 -559
  349. package/src/components/composites/date-picker/field-shell.tsx +9 -3
  350. package/src/components/composites/date-picker/range-panel.tsx +23 -8
  351. package/src/components/composites/date-picker/time-core.tsx +2 -0
  352. package/src/components/composites/dialog/Dialog.tsx +30 -15
  353. package/src/components/composites/dialog/Dialog.usage.md +17 -0
  354. package/src/components/composites/dialog/dialog.css +176 -172
  355. package/src/components/composites/dropdown/Dropdown.tsx +184 -0
  356. package/src/components/composites/dropdown/Dropdown.usage.md +19 -0
  357. package/src/components/composites/dropdown/dropdown.css +65 -0
  358. package/src/components/composites/dropdown/menu-panel.tsx +255 -0
  359. package/src/components/composites/dropdown/types.ts +95 -0
  360. package/src/components/composites/emoji-picker/EmojiPickerPanel.tsx +153 -0
  361. package/src/components/composites/emoji-picker/EmojiPickerPanel.usage.md +26 -0
  362. package/src/components/composites/emoji-picker/category-icons.ts +29 -0
  363. package/src/components/composites/emoji-picker/data.ts +83 -0
  364. package/src/components/composites/emoji-picker/dom.ts +79 -0
  365. package/src/components/composites/emoji-picker/getEmojiUrl.ts +17 -0
  366. package/src/components/composites/emoji-picker/navigation.ts +86 -0
  367. package/src/components/composites/emoji-picker/picker.ts +169 -0
  368. package/src/components/composites/emoji-picker/react/category-bar.tsx +77 -0
  369. package/src/components/composites/emoji-picker/react/useEmojiPicker.ts +139 -0
  370. package/src/components/composites/emoji-picker/scaffold.ts +74 -0
  371. package/src/components/composites/emoji-picker/search.ts +79 -0
  372. package/src/components/composites/emoji-picker/styles.css +221 -0
  373. package/src/components/composites/emoji-picker/types.ts +14 -0
  374. package/src/components/composites/modal/Modal.tsx +24 -13
  375. package/src/components/composites/modal/Modal.usage.md +24 -0
  376. package/src/components/composites/modal/modal.css +11 -7
  377. package/src/components/composites/pagination/Pagination.tsx +6 -11
  378. package/src/components/composites/pagination/Pagination.usage.md +12 -0
  379. package/src/components/composites/pagination/pagination.css +42 -38
  380. package/src/components/composites/popover/Popover.tsx +22 -7
  381. package/src/components/composites/popover/Popover.usage.md +15 -0
  382. package/src/components/composites/popover/popover.css +69 -65
  383. package/src/components/composites/select/MultiSelect.tsx +13 -5
  384. package/src/components/composites/select/MultiSelect.usage.md +12 -0
  385. package/src/components/composites/select/Select.tsx +23 -7
  386. package/src/components/composites/select/Select.usage.md +20 -0
  387. package/src/components/composites/select/core/index.ts +1 -1
  388. package/src/components/composites/select/core/menu.tsx +8 -6
  389. package/src/components/composites/select/core/panel.tsx +25 -26
  390. package/src/components/composites/select/core/trigger.tsx +36 -24
  391. package/src/components/composites/select/core/types.ts +17 -15
  392. package/src/components/composites/select/core/use-listbox.ts +22 -21
  393. package/src/components/composites/select/select.css +291 -386
  394. package/src/components/composites/sheet/Sheet.tsx +28 -18
  395. package/src/components/composites/sheet/Sheet.usage.md +15 -0
  396. package/src/components/composites/sheet/sheet.css +47 -23
  397. package/src/components/composites/sheet/use-sheet-drag.ts +19 -15
  398. package/src/components/composites/table/Table.tsx +17 -6
  399. package/src/components/composites/table/Table.usage.md +19 -0
  400. package/src/components/composites/table/table.css +333 -323
  401. package/src/components/composites/tabs/Tabs.tsx +31 -23
  402. package/src/components/composites/tabs/Tabs.usage.md +13 -0
  403. package/src/components/composites/tabs/tabs.css +163 -156
  404. package/src/components/composites/toast/Toast.tsx +48 -51
  405. package/src/components/composites/toast/Toast.usage.md +23 -0
  406. package/src/components/composites/toast/toast-store.usage.md +16 -0
  407. package/src/components/composites/toast/toast.css +237 -233
  408. package/src/components/composites/tooltip/Tooltip.tsx +13 -8
  409. package/src/components/composites/tooltip/Tooltip.usage.md +14 -0
  410. package/src/components/composites/tooltip/tooltip-host.tsx +29 -61
  411. package/src/components/composites/tooltip/tooltip-store.ts +10 -0
  412. package/src/components/composites/tooltip/tooltip.css +79 -78
  413. package/src/components/compound/support-rail/SupportRail.tsx +343 -0
  414. package/src/components/compound/support-rail/SupportRail.usage.md +18 -0
  415. package/src/components/compound/support-rail/support-rail.css +421 -0
  416. package/src/components/dev/MotionDevtools.tsx +3 -1
  417. package/src/components/dev/MotionDevtools.usage.md +16 -0
  418. package/src/components/dev/motion-devtools.css +237 -233
  419. package/src/components/expressive/confetti/Confetti.tsx +727 -0
  420. package/src/components/expressive/confetti/Confetti.usage.md +18 -0
  421. package/src/components/expressive/confetti/confetti.css +45 -0
  422. package/src/components/expressive/facebook-feed/FacebookFeed.tsx +200 -0
  423. package/src/components/expressive/facebook-feed/FacebookFeed.usage.md +18 -0
  424. package/src/components/expressive/facebook-feed/chrome.tsx +120 -0
  425. package/src/components/expressive/facebook-feed/facebook-feed.css +880 -0
  426. package/src/components/expressive/facebook-feed/icons.tsx +145 -0
  427. package/src/components/expressive/facebook-feed/post.tsx +213 -0
  428. package/src/components/expressive/facebook-feed/reel.tsx +199 -0
  429. package/src/components/expressive/facebook-feed/story.tsx +132 -0
  430. package/src/components/expressive/flow-field/FlowField.tsx +348 -0
  431. package/src/components/expressive/flow-field/FlowField.usage.md +19 -0
  432. package/src/components/expressive/flow-field/flow-field.css +49 -0
  433. package/src/components/expressive/instagram-feed/InstagramFeed.tsx +374 -0
  434. package/src/components/expressive/instagram-feed/InstagramFeed.usage.md +18 -0
  435. package/src/components/expressive/instagram-feed/instagram-feed.css +378 -0
  436. package/src/components/expressive/lens/Lens.tsx +415 -0
  437. package/src/components/expressive/lens/Lens.usage.md +20 -0
  438. package/src/components/expressive/lens/lens.css +119 -0
  439. package/src/components/expressive/morphing-text/MorphingText.tsx +328 -0
  440. package/src/components/expressive/morphing-text/MorphingText.usage.md +19 -0
  441. package/src/components/expressive/morphing-text/morphing-text.css +84 -0
  442. package/src/components/expressive/odometer/Odometer.tsx +158 -0
  443. package/src/components/expressive/odometer/Odometer.usage.md +17 -0
  444. package/src/components/expressive/odometer/odometer.css +61 -0
  445. package/src/components/expressive/tiktok/TikTok.tsx +542 -0
  446. package/src/components/expressive/tiktok/TikTok.usage.md +17 -0
  447. package/src/components/expressive/tiktok/glyphs.tsx +163 -0
  448. package/src/components/expressive/tiktok/tiktok.css +662 -0
  449. package/src/components/expressive/typing-lines/TypingLines.tsx +0 -0
  450. package/src/components/expressive/typing-lines/TypingLines.usage.md +17 -0
  451. package/src/components/expressive/typing-lines/typing-lines.css +92 -0
  452. package/src/components/expressive/weight-field/WeightField.tsx +41 -0
  453. package/src/components/expressive/weight-field/WeightField.usage.md +20 -0
  454. package/src/components/expressive/weight-field/weight-field.css +84 -0
  455. package/src/components/expressive/youtube/YouTube.tsx +192 -0
  456. package/src/components/expressive/youtube/YouTube.usage.md +18 -0
  457. package/src/components/expressive/youtube/format.ts +22 -0
  458. package/src/components/expressive/youtube/glyphs.tsx +235 -0
  459. package/src/components/expressive/youtube/media.tsx +18 -0
  460. package/src/components/expressive/youtube/post.tsx +282 -0
  461. package/src/components/expressive/youtube/short.tsx +212 -0
  462. package/src/components/expressive/youtube/video.tsx +75 -0
  463. package/src/components/expressive/youtube/youtube.css +611 -0
  464. package/src/components/internal/collection/collection.ts +44 -0
  465. package/src/components/internal/glass/glass.css +88 -84
  466. package/src/components/internal/hooks/use-media-query.ts +20 -0
  467. package/src/components/internal/hooks/use-typeahead.ts +28 -0
  468. package/src/components/internal/icon/Icon.tsx +2 -0
  469. package/src/components/internal/icon/IconSlot.tsx +2 -0
  470. package/src/components/internal/icon/icon.css +34 -30
  471. package/src/components/internal/menu/menu-row.tsx +34 -0
  472. package/src/components/internal/menu/menu-surface.css +127 -0
  473. package/src/components/internal/overlay/focus.ts +26 -10
  474. package/src/components/internal/overlay/layer.tsx +50 -19
  475. package/src/components/internal/overlay/modal.tsx +14 -12
  476. package/src/components/internal/overlay/overlay.css +24 -20
  477. package/src/components/internal/overlay/position.ts +19 -9
  478. package/src/components/internal/overlay/trigger.css +13 -0
  479. package/src/components/internal/support/types.ts +16 -0
  480. package/src/components/internal/utils/activation.ts +78 -0
  481. package/src/components/primitives/avatar/Avatar.tsx +2 -0
  482. package/src/components/primitives/avatar/Avatar.usage.md +12 -0
  483. package/src/components/primitives/avatar/AvatarGroup.tsx +3 -1
  484. package/src/components/primitives/avatar/AvatarGroup.usage.md +15 -0
  485. package/src/components/primitives/avatar/avatar.css +179 -174
  486. package/src/components/primitives/badge/Badge.tsx +3 -1
  487. package/src/components/primitives/badge/Badge.usage.md +14 -0
  488. package/src/components/primitives/badge/CountBadge.tsx +2 -2
  489. package/src/components/primitives/badge/CountBadge.usage.md +13 -0
  490. package/src/components/primitives/badge/StatusBadge.tsx +3 -1
  491. package/src/components/primitives/badge/StatusBadge.usage.md +14 -0
  492. package/src/components/primitives/badge/badge.css +166 -160
  493. package/src/components/primitives/badge/digit-strip.css +65 -0
  494. package/src/components/primitives/badge/{odometer.tsx → digit-strip.tsx} +3 -3
  495. package/src/components/primitives/button/Button.tsx +2 -0
  496. package/src/components/primitives/button/Button.usage.md +14 -0
  497. package/src/components/primitives/button/button.css +272 -246
  498. package/src/components/primitives/checkbox/Checkbox.tsx +3 -1
  499. package/src/components/primitives/checkbox/Checkbox.usage.md +12 -0
  500. package/src/components/primitives/checkbox/check-glyph.tsx +1 -0
  501. package/src/components/primitives/checkbox/checkbox.css +158 -153
  502. package/src/components/primitives/collapse/Collapse.tsx +3 -1
  503. package/src/components/primitives/collapse/Collapse.usage.md +17 -0
  504. package/src/components/primitives/collapse/collapse.css +70 -61
  505. package/src/components/primitives/collapse/collapse.typecheck.tsx +2 -0
  506. package/src/components/primitives/input/NumberField.tsx +18 -5
  507. package/src/components/primitives/input/NumberField.usage.md +12 -0
  508. package/src/components/primitives/input/OtpField.tsx +2 -0
  509. package/src/components/primitives/input/OtpField.usage.md +12 -0
  510. package/src/components/primitives/input/TextField.tsx +16 -4
  511. package/src/components/primitives/input/TextField.usage.md +13 -0
  512. package/src/components/primitives/input/field-chrome.tsx +11 -2
  513. package/src/components/primitives/input/input.css +296 -318
  514. package/src/components/primitives/radio-group/RadioGroup.tsx +20 -44
  515. package/src/components/primitives/radio-group/RadioGroup.usage.md +13 -0
  516. package/src/components/primitives/radio-group/radio-group.css +275 -276
  517. package/src/components/primitives/tag/Tag.tsx +10 -6
  518. package/src/components/primitives/tag/Tag.usage.md +14 -0
  519. package/src/components/primitives/tag/ToggleTag.tsx +4 -2
  520. package/src/components/primitives/tag/ToggleTag.usage.md +14 -0
  521. package/src/components/primitives/tag/tag.css +209 -231
  522. package/src/components/primitives/textarea/Textarea.tsx +17 -7
  523. package/src/components/primitives/textarea/Textarea.usage.md +12 -0
  524. package/src/components/primitives/textarea/textarea.css +205 -211
  525. package/src/components/primitives/toggle/Toggle.tsx +3 -1
  526. package/src/components/primitives/toggle/Toggle.usage.md +12 -0
  527. package/src/components/primitives/toggle/toggle.css +139 -135
  528. package/src/engine/animate.ts +40 -13
  529. package/src/engine/ease.ts +1 -0
  530. package/src/engine/flip.ts +32 -15
  531. package/src/engine/index.ts +2 -1
  532. package/src/engine/loop.ts +97 -0
  533. package/src/mcp/server.ts +315 -221
  534. package/src/motion/element.tsx +1 -0
  535. package/src/motion/flip.ts +29 -10
  536. package/src/motion/glide.tsx +11 -14
  537. package/src/motion/glide.usage.md +15 -0
  538. package/src/motion/motion-timing.ts +3 -3
  539. package/src/motion/presence.tsx +38 -21
  540. package/src/motion/presets.ts +13 -0
  541. package/src/motion/timing.ts +1 -0
  542. package/src/motion/use-motion.ts +16 -3
  543. package/src/styles.css +5 -0
  544. package/src/tokens/avatar.css +20 -16
  545. package/src/tokens/color.css +67 -56
  546. package/src/tokens/component-styles.generated.ts +270 -0
  547. package/src/tokens/elevation.css +28 -17
  548. package/src/tokens/fonts.css +1 -1
  549. package/src/tokens/glass.css +19 -15
  550. package/src/tokens/icons.css +8 -4
  551. package/src/tokens/layers.css +9 -4
  552. package/src/tokens/motion-scale.ts +4 -0
  553. package/src/tokens/motion-tokens.ts +42 -12
  554. package/src/tokens/motion-tokens.usage.md +16 -0
  555. package/src/tokens/motion.css +63 -45
  556. package/src/tokens/radius.css +12 -8
  557. package/src/tokens/semantic.css +62 -54
  558. package/src/tokens/spacing.css +25 -21
  559. package/src/tokens/theme-tokens.generated.ts +1278 -0
  560. package/src/tokens/theme.tsx +83 -0
  561. package/src/tokens/theme.usage.md +36 -0
  562. package/src/tokens/typography.css +53 -49
  563. package/dist/chunk-2ERBBFZS.js.map +0 -1
  564. package/dist/chunk-2F5PITAO.js.map +0 -1
  565. package/dist/chunk-2QWJ6FAX.js.map +0 -1
  566. package/dist/chunk-356HZMT4.js.map +0 -1
  567. package/dist/chunk-62P3KD57.js.map +0 -1
  568. package/dist/chunk-7SZCJ7WI.js.map +0 -1
  569. package/dist/chunk-CONSWNIV.js.map +0 -1
  570. package/dist/chunk-FTOAUJL5.js.map +0 -1
  571. package/dist/chunk-I4XQ4PV2.js.map +0 -1
  572. package/dist/chunk-K5X2GCXU.js.map +0 -1
  573. package/dist/chunk-NEF5XAHG.js.map +0 -1
  574. package/dist/chunk-NNXJCLTV.js.map +0 -1
  575. package/dist/chunk-OMHQ4U4J.js.map +0 -1
  576. package/dist/chunk-PMECHR3A.js.map +0 -1
  577. package/dist/chunk-QDK66S4G.js.map +0 -1
  578. package/dist/chunk-RCONNA7I.js.map +0 -1
  579. package/dist/chunk-S5ZTZANS.js.map +0 -1
  580. package/dist/chunk-UXONUUPI.js.map +0 -1
  581. package/dist/chunk-VTJTGVZZ.js.map +0 -1
  582. package/dist/chunk-WM5J5TDI.js.map +0 -1
  583. package/dist/chunk-XWUWYSCT.js.map +0 -1
  584. package/dist/chunk-Y7AJQVWJ.js.map +0 -1
  585. package/dist/chunk-YGCVWGUG.js.map +0 -1
  586. package/dist/chunk-YGGCQNNU.js.map +0 -1
  587. package/dist/chunk-ZCOUPPTI.js.map +0 -1
  588. package/dist/count-badge.d.ts +0 -13
  589. package/dist/date-range-field.d.ts +0 -33
  590. package/dist/field-chrome-CMPOQSLs.d.ts +0 -28
  591. package/dist/field-shell-Cuda-feL.d.ts +0 -24
  592. package/dist/glide.d.ts +0 -15
  593. package/dist/motion-devtools.d.ts +0 -51
  594. package/dist/status-badge.d.ts +0 -19
  595. package/dist/toast.d.ts +0 -12
  596. package/llms.txt +0 -220
  597. package/src/components/primitives/badge/odometer.css +0 -62
@@ -0,0 +1,542 @@
1
+ 'use client';
2
+
3
+ import './tiktok.css';
4
+
5
+ import {
6
+ useCallback,
7
+ useEffect,
8
+ useRef,
9
+ useState,
10
+ type CSSProperties,
11
+ type HTMLAttributes,
12
+ type KeyboardEvent as ReactKeyboardEvent,
13
+ type ReactNode,
14
+ type PointerEvent as ReactPointerEvent,
15
+ } from 'react';
16
+
17
+ import type { DataAttributes } from '../../../dom-props';
18
+ import { animate, set, startDrag, type PanInfo } from '../../../engine';
19
+ import { UIMotion } from '../../../tokens/motion-tokens';
20
+ import { useControllable } from '../../internal/hooks/use-controllable';
21
+ import { cx } from '../../internal/utils/cx';
22
+ import {
23
+ AudibleGlyph,
24
+ BookmarkGlyph,
25
+ CommentGlyph,
26
+ HeartGlyph,
27
+ MenuGlyph,
28
+ MutedGlyph,
29
+ NextGlyph,
30
+ NoteGlyph,
31
+ PinGlyph,
32
+ PlusGlyph,
33
+ PreviousGlyph,
34
+ SearchGlyph,
35
+ ShareGlyph,
36
+ } from './glyphs';
37
+
38
+ const FIRST_SLIDE = 1;
39
+ const MAX_SLIDES = 10;
40
+ const SINGLE_SLIDE = 1;
41
+ const THOUSAND = 1000;
42
+ const ABBREVIATE_FROM = 10000;
43
+ const MILLION = 1000000;
44
+ const ABBREVIATED_DECIMALS = 1;
45
+ const DRAG_RESISTANCE = 0.32;
46
+ const PAGE_FRACTION = 0.28;
47
+ const FLING_SPEED = 420;
48
+ const PREVIOUS_STEP = -1;
49
+ const NEXT_STEP = 1;
50
+
51
+ const LIKES_LABEL = 'Like';
52
+ const COMMENTS_LABEL = 'Comment';
53
+ const SAVES_LABEL = 'Save';
54
+ const SHARES_LABEL = 'Share';
55
+ const FOLLOW_LABEL = 'Follow';
56
+ const MENU_LABEL = 'Open menu';
57
+ const SEARCH_LABEL = 'Search';
58
+ const PREVIOUS_LABEL = 'Previous photo';
59
+ const NEXT_LABEL = 'Next photo';
60
+ const MUTE_LABEL = 'Mute';
61
+ const CAROUSEL_ROLE_DESCRIPTION = 'carousel';
62
+ const SLIDE_ROLE_DESCRIPTION = 'slide';
63
+ const TRANSLATION_LABEL = 'See translation';
64
+ const MORE_LABEL = 'more';
65
+
66
+ const DESKTOP_RATIO: TikTokRatio = '3:2';
67
+ const MOBILE_RATIO: TikTokRatio = '4:3';
68
+
69
+ const clamp = (value: number, min: number, max: number) => (value < min ? min : value > max ? max : value);
70
+
71
+ const pageTiming = () => ({ duration: UIMotion.dur.slow, ease: UIMotion.ease.glide });
72
+
73
+ function abbreviate(value: number): string {
74
+ const total = Math.max(0, Math.round(value));
75
+ const short = (divisor: number) => (total / divisor).toFixed(ABBREVIATED_DECIMALS).replace(/\.0$/, '');
76
+ if (total >= MILLION) return `${short(MILLION)}M`;
77
+ if (total >= ABBREVIATE_FROM) return `${short(THOUSAND)}K`;
78
+ return String(total);
79
+ }
80
+
81
+ function slideCount(media: ReactNode, slides: number | undefined): number {
82
+ const supplied = Array.isArray(media) ? media.length : 0;
83
+ const asked = slides ? Math.round(slides) : SINGLE_SLIDE;
84
+ return clamp(Math.max(supplied, asked), SINGLE_SLIDE, MAX_SLIDES);
85
+ }
86
+
87
+ function slideMedia(media: ReactNode, at: number): ReactNode {
88
+ if (!Array.isArray(media)) return at === 0 ? media : undefined;
89
+ return media[at];
90
+ }
91
+
92
+ function renderMedia(media: ReactNode): ReactNode {
93
+ if (media === undefined || media === null || media === false) return <span className="tiktok__blank" />;
94
+ if (typeof media === 'string') return <img src={media} alt="" />;
95
+ return media;
96
+ }
97
+
98
+ function limitOffset(offset: number, from: number, count: number, width: number): number {
99
+ const min = -(count - 1 - from) * width;
100
+ const max = from * width;
101
+ if (offset < min) return min + (offset - min) * DRAG_RESISTANCE;
102
+ if (offset > max) return max + (offset - max) * DRAG_RESISTANCE;
103
+ return offset;
104
+ }
105
+
106
+ function landingIndex(from: number, info: PanInfo, width: number, count: number): number {
107
+ const travelled = info.offset.x / width;
108
+ const flung = Math.abs(info.velocity.x) > FLING_SPEED;
109
+ if (!flung && Math.abs(travelled) < PAGE_FRACTION) return from;
110
+ const step = info.offset.x < 0 ? NEXT_STEP : PREVIOUS_STEP;
111
+ return clamp(from + step, 0, count - 1);
112
+ }
113
+
114
+ /** The surface of the platform being reproduced. */
115
+ export type TikTokSurface = 'desktop' | 'mobile';
116
+
117
+ /** Aspect ratio of the post media inside the stage. */
118
+ export type TikTokRatio = '3:2' | '4:3' | '1:1' | '16:9' | '9:16' | '3:4';
119
+
120
+ /** The rail and chrome actions that carry no state of their own. */
121
+ export type TikTokAction = 'comment' | 'share' | 'menu' | 'search';
122
+
123
+ export interface TikTokOwnProps {
124
+ /** Which platform surface to reproduce. Desktop is the 1584x912 web player with the photo carousel; mobile is the 452x822 mobile-web viewport. */
125
+ surface?: TikTokSurface;
126
+ /** Aspect ratio of the media inside the frame. Defaults to 3:2 on desktop and 4:3 on mobile. */
127
+ ratio?: TikTokRatio;
128
+ /** Creator name shown over the media. */
129
+ name?: string;
130
+ /** Post caption. Ellipsised to one line on desktop and two on mobile until "more" is pressed. */
131
+ caption?: string;
132
+ /** Desktop only. Place name in the pin chip above the creator name. */
133
+ location?: string;
134
+ /** Mobile only. Music attribution shown first on the sound line. */
135
+ music?: string;
136
+ /** Mobile only. Sound title shown after the music attribution. */
137
+ sound?: string;
138
+ /** Like count. Printed exactly below 10,000, then abbreviated as the platform does. */
139
+ likes?: number;
140
+ /** Comment count. */
141
+ comments?: number;
142
+ /** Desktop only. Save count - the mobile rail has no save action. */
143
+ saves?: number;
144
+ /** Share count. */
145
+ shares?: number;
146
+ /** Post media: a URL string rendered as a decorative image, or a node you render yourself. On desktop an array supplies one entry per carousel slide. */
147
+ media?: ReactNode;
148
+ /** Creator avatar: a URL string, or a node you render yourself. */
149
+ avatar?: ReactNode;
150
+ /** Sound artwork on the disc at the foot of the rail: a URL string, or a node you render yourself. */
151
+ sticker?: ReactNode;
152
+ /** Desktop only. Number of carousel slides. Raised to the length of `media` when that is an array. */
153
+ slides?: number;
154
+ /** Desktop only. Controlled 1-based carousel position. */
155
+ slide?: number;
156
+ /** Desktop only. Uncontrolled starting carousel position. */
157
+ defaultSlide?: number;
158
+ /** Desktop only. Fires with the new 1-based position when the carousel pages. */
159
+ onSlideChange?: (slide: number) => void;
160
+ /** Desktop only. Controlled state of the mute control. The component never plays or pauses media - wire this to your own player. */
161
+ muted?: boolean;
162
+ /** Desktop only. Uncontrolled starting state of the mute control. */
163
+ defaultMuted?: boolean;
164
+ /** Desktop only. Fires when the mute control is pressed. */
165
+ onMutedChange?: (muted: boolean) => void;
166
+ /** Desktop only. Renders the platform's "See translation" line under the frame. */
167
+ translation?: boolean;
168
+ /** Controlled like state. The displayed like count adds one while this is on. */
169
+ liked?: boolean;
170
+ /** Uncontrolled initial like state. @default false */
171
+ defaultLiked?: boolean;
172
+ /** Fires when the heart toggles the like. */
173
+ onLikedChange?: (liked: boolean) => void;
174
+ /** Desktop only. Controlled save state for the bookmark on the rail. */
175
+ saved?: boolean;
176
+ /** Uncontrolled initial save state. @default false */
177
+ defaultSaved?: boolean;
178
+ /** Fires when the bookmark toggles. */
179
+ onSavedChange?: (saved: boolean) => void;
180
+ /** Controlled follow state for the plus badge on the creator avatar. */
181
+ followed?: boolean;
182
+ /** Uncontrolled initial follow state. @default false */
183
+ defaultFollowed?: boolean;
184
+ /** Fires when the follow badge toggles. */
185
+ onFollowedChange?: (followed: boolean) => void;
186
+ /** Fires for the actions that carry no state: comment, share, menu, search. */
187
+ onAction?: (action: TikTokAction) => void;
188
+ /** Extra class(es) merged onto the root. */
189
+ className?: string;
190
+ /** Inline styles merged onto the root. */
191
+ style?: CSSProperties;
192
+ }
193
+
194
+ export interface TikTokProps extends TikTokOwnProps {
195
+ /** Standard element attributes (aria-*, data-*, id, ...) forwarded to the root. */
196
+ htmlProps?: Omit<HTMLAttributes<HTMLDivElement>, keyof TikTokOwnProps> & DataAttributes;
197
+ }
198
+
199
+ export function TikTok({
200
+ surface = 'desktop',
201
+ ratio,
202
+ name = '',
203
+ caption = '',
204
+ location = '',
205
+ music = '',
206
+ sound = '',
207
+ likes = 0,
208
+ comments = 0,
209
+ saves = 0,
210
+ shares = 0,
211
+ media,
212
+ avatar,
213
+ sticker,
214
+ slides,
215
+ slide,
216
+ defaultSlide = FIRST_SLIDE,
217
+ onSlideChange,
218
+ muted,
219
+ defaultMuted = true,
220
+ onMutedChange,
221
+ translation = true,
222
+ liked,
223
+ defaultLiked = false,
224
+ onLikedChange,
225
+ saved,
226
+ defaultSaved = false,
227
+ onSavedChange,
228
+ followed,
229
+ defaultFollowed = false,
230
+ onFollowedChange,
231
+ onAction,
232
+ className,
233
+ style,
234
+ htmlProps,
235
+ }: TikTokProps) {
236
+ const desktop = surface === 'desktop';
237
+ const count = desktop ? slideCount(media, slides) : SINGLE_SLIDE;
238
+ const frameRatio = ratio ?? (desktop ? DESKTOP_RATIO : MOBILE_RATIO);
239
+
240
+ const [position, setPosition] = useControllable(slide, defaultSlide, onSlideChange);
241
+ const [quiet, setQuiet] = useControllable(muted, defaultMuted, onMutedChange);
242
+ const [hearted, setHearted] = useControllable(liked, defaultLiked, onLikedChange);
243
+ const [bookmarked, setBookmarked] = useControllable(saved, defaultSaved, onSavedChange);
244
+ const [following, setFollowing] = useControllable(followed, defaultFollowed, onFollowedChange);
245
+ const [open, setOpen] = useState(false);
246
+
247
+ const index = clamp(Math.round(position), FIRST_SLIDE, count) - FIRST_SLIDE;
248
+ const viewportRef = useRef<HTMLDivElement>(null);
249
+ const trackRef = useRef<HTMLDivElement>(null);
250
+ const settled = useRef<number | null>(null);
251
+
252
+ useEffect(() => {
253
+ const track = trackRef.current;
254
+ const viewport = viewportRef.current;
255
+ if (!track || !viewport || settled.current === index) return;
256
+ const first = settled.current === null;
257
+ settled.current = index;
258
+ const target = -index * viewport.clientWidth;
259
+ if (first) {
260
+ set(track, { x: [target] });
261
+ return;
262
+ }
263
+ const playback = animate(track, { x: [target], timing: pageTiming() });
264
+ return () => playback.stop();
265
+ }, [index]);
266
+
267
+ const goTo = useCallback(
268
+ (next: number) => {
269
+ const bounded = clamp(next, 0, count - 1);
270
+ if (bounded !== index) setPosition(bounded + FIRST_SLIDE);
271
+ },
272
+ [count, index, setPosition],
273
+ );
274
+
275
+ const onPointerDown = useCallback(
276
+ (event: ReactPointerEvent<HTMLDivElement>) => {
277
+ const track = trackRef.current;
278
+ const viewport = viewportRef.current;
279
+ if (count < 2 || event.button !== 0 || !track || !viewport) return;
280
+ const width = viewport.clientWidth;
281
+ if (!width) return;
282
+ const from = index;
283
+ startDrag(event.nativeEvent, {
284
+ onMove: (info) => {
285
+ set(track, { x: [-from * width + limitOffset(info.offset.x, from, count, width)] });
286
+ },
287
+ onEnd: (info) => {
288
+ const landed = landingIndex(from, info, width, count);
289
+ settled.current = landed;
290
+ animate(track, { x: [-landed * width], timing: pageTiming() });
291
+ if (landed !== from) setPosition(landed + FIRST_SLIDE);
292
+ },
293
+ });
294
+ },
295
+ [count, index, setPosition],
296
+ );
297
+
298
+ const onKeyDown = useCallback(
299
+ (event: ReactKeyboardEvent<HTMLDivElement>) => {
300
+ if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;
301
+ event.preventDefault();
302
+ goTo(index + (event.key === 'ArrowLeft' ? PREVIOUS_STEP : NEXT_STEP));
303
+ },
304
+ [goTo, index],
305
+ );
306
+
307
+ const positions = Array.from({ length: count }, (_, at) => at);
308
+
309
+ const rail = (
310
+ <ul className="tiktok__rail">
311
+ <li className="tiktok__creator">
312
+ <span className="tiktok__avatar" aria-hidden="true">
313
+ {renderMedia(avatar)}
314
+ </span>
315
+ <button
316
+ type="button"
317
+ className="tiktok__button tiktok__follow"
318
+ aria-label={FOLLOW_LABEL}
319
+ aria-pressed={following}
320
+ onClick={() => setFollowing(!following)}
321
+ >
322
+ <PlusGlyph className="tiktok__plus" />
323
+ </button>
324
+ </li>
325
+ <RailAction
326
+ surface={surface}
327
+ label={LIKES_LABEL}
328
+ count={likes + (hearted ? 1 : 0)}
329
+ pressed={hearted}
330
+ onClick={() => setHearted(!hearted)}
331
+ >
332
+ <HeartGlyph className="tiktok__glyph" />
333
+ </RailAction>
334
+ <RailAction surface={surface} label={COMMENTS_LABEL} count={comments} onClick={() => onAction?.('comment')}>
335
+ <CommentGlyph className="tiktok__glyph" holeClassName="tiktok__hole" />
336
+ </RailAction>
337
+ {desktop ? (
338
+ <RailAction
339
+ surface={surface}
340
+ label={SAVES_LABEL}
341
+ count={saves}
342
+ pressed={bookmarked}
343
+ onClick={() => setBookmarked(!bookmarked)}
344
+ >
345
+ <BookmarkGlyph className="tiktok__glyph" />
346
+ </RailAction>
347
+ ) : null}
348
+ <RailAction surface={surface} label={SHARES_LABEL} count={shares} onClick={() => onAction?.('share')}>
349
+ <ShareGlyph className="tiktok__glyph" />
350
+ </RailAction>
351
+ <li className="tiktok__disc" aria-hidden="true">
352
+ {renderMedia(sticker)}
353
+ </li>
354
+ </ul>
355
+ );
356
+
357
+ const captionRow = caption ? (
358
+ <p className="tiktok__captionrow">
359
+ <span className={cx('tiktok__caption', open && 'tiktok__caption--open')}>{caption}</span>
360
+ {open ? null : (
361
+ <button type="button" className="tiktok__more" onClick={() => setOpen(true)}>
362
+ {MORE_LABEL}
363
+ </button>
364
+ )}
365
+ </p>
366
+ ) : null;
367
+
368
+ const frame = (
369
+ <div className="tiktok__frame">
370
+ <div
371
+ className="tiktok__viewport"
372
+ ref={viewportRef}
373
+ role={count > 1 ? 'group' : undefined}
374
+ aria-roledescription={count > 1 ? CAROUSEL_ROLE_DESCRIPTION : undefined}
375
+ aria-label={count > 1 ? name || CAROUSEL_ROLE_DESCRIPTION : undefined}
376
+ tabIndex={count > 1 ? 0 : undefined}
377
+ onKeyDown={count > 1 ? onKeyDown : undefined}
378
+ onPointerDown={count > 1 ? onPointerDown : undefined}
379
+ >
380
+ <div className="tiktok__track" ref={trackRef}>
381
+ {positions.map((at) => (
382
+ <div
383
+ key={at}
384
+ className="tiktok__slide"
385
+ role={count > 1 ? 'group' : undefined}
386
+ aria-roledescription={count > 1 ? SLIDE_ROLE_DESCRIPTION : undefined}
387
+ aria-label={count > 1 ? `${at + FIRST_SLIDE} of ${count}` : undefined}
388
+ aria-hidden={count > 1 && at !== index ? true : undefined}
389
+ >
390
+ <div className="tiktok__fill" aria-hidden="true">
391
+ {renderMedia(slideMedia(media, at))}
392
+ </div>
393
+ <div className="tiktok__stack">
394
+ <div className="tiktok__fit" data-ratio={frameRatio}>
395
+ {renderMedia(slideMedia(media, at))}
396
+ </div>
397
+ </div>
398
+ </div>
399
+ ))}
400
+ </div>
401
+ </div>
402
+
403
+ {desktop && count > 1 ? (
404
+ <div className="tiktok__pager">
405
+ <button
406
+ type="button"
407
+ className="tiktok__arrow"
408
+ aria-label={PREVIOUS_LABEL}
409
+ disabled={index === 0}
410
+ onClick={() => goTo(index + PREVIOUS_STEP)}
411
+ >
412
+ <PreviousGlyph className="tiktok__chevron" />
413
+ </button>
414
+ <span className="tiktok__dots" aria-hidden="true">
415
+ {positions.map((at) => (
416
+ <span key={at} className={cx('tiktok__dot', at === index && 'tiktok__dot--on')} />
417
+ ))}
418
+ </span>
419
+ <button
420
+ type="button"
421
+ className="tiktok__arrow"
422
+ aria-label={NEXT_LABEL}
423
+ disabled={index === count - 1}
424
+ onClick={() => goTo(index + NEXT_STEP)}
425
+ >
426
+ <NextGlyph className="tiktok__chevron" />
427
+ </button>
428
+ </div>
429
+ ) : null}
430
+
431
+ {desktop ? (
432
+ <div className="tiktok__meta">
433
+ {location ? (
434
+ <p className="tiktok__place">
435
+ <span className="tiktok__pin">
436
+ <PinGlyph className="tiktok__pinmark" />
437
+ </span>
438
+ {location}
439
+ </p>
440
+ ) : null}
441
+ {name ? <p className="tiktok__name">{name}</p> : null}
442
+ {captionRow}
443
+ </div>
444
+ ) : null}
445
+ </div>
446
+ );
447
+
448
+ const mobileMeta = (
449
+ <div className="tiktok__meta">
450
+ {name ? <p className="tiktok__name">{name}</p> : null}
451
+ {captionRow}
452
+ {music || sound ? (
453
+ <p className="tiktok__music">
454
+ <NoteGlyph className="tiktok__note" />
455
+ {music ? <span>{music}</span> : null}
456
+ {sound ? <span className="tiktok__sound">{sound}</span> : null}
457
+ </p>
458
+ ) : null}
459
+ </div>
460
+ );
461
+
462
+ return (
463
+ <div
464
+ className={cx('tiktok', desktop ? 'tiktok--desktop' : 'tiktok--mobile', className)}
465
+ style={style}
466
+ {...htmlProps}
467
+ >
468
+ <div className="tiktok__stage">
469
+ {desktop ? (
470
+ <button
471
+ type="button"
472
+ className="tiktok__mute"
473
+ aria-label={MUTE_LABEL}
474
+ aria-pressed={quiet}
475
+ onClick={() => setQuiet(!quiet)}
476
+ >
477
+ {quiet ? <MutedGlyph className="tiktok__speaker" /> : <AudibleGlyph className="tiktok__speaker" />}
478
+ </button>
479
+ ) : null}
480
+ {frame}
481
+ {desktop ? null : (
482
+ <>
483
+ <span className="tiktok__scrim-top" aria-hidden="true" />
484
+ <span className="tiktok__scrim-bottom" aria-hidden="true" />
485
+ <div className="tiktok__header">
486
+ <button
487
+ type="button"
488
+ className="tiktok__button"
489
+ aria-label={MENU_LABEL}
490
+ onClick={() => onAction?.('menu')}
491
+ >
492
+ <MenuGlyph className="tiktok__nav" />
493
+ </button>
494
+ <button
495
+ type="button"
496
+ className="tiktok__button"
497
+ aria-label={SEARCH_LABEL}
498
+ onClick={() => onAction?.('search')}
499
+ >
500
+ <SearchGlyph className="tiktok__nav" />
501
+ </button>
502
+ </div>
503
+ </>
504
+ )}
505
+ {rail}
506
+ {desktop ? null : mobileMeta}
507
+ {desktop && translation ? (
508
+ <p className="tiktok__translate" aria-hidden="true">
509
+ {TRANSLATION_LABEL}
510
+ </p>
511
+ ) : null}
512
+ </div>
513
+ </div>
514
+ );
515
+ }
516
+
517
+ function RailAction({
518
+ surface,
519
+ label,
520
+ count,
521
+ pressed,
522
+ onClick,
523
+ children,
524
+ }: {
525
+ surface: TikTokSurface;
526
+ label: string;
527
+ count: number;
528
+ pressed?: boolean;
529
+ onClick: () => void;
530
+ children: ReactNode;
531
+ }) {
532
+ return (
533
+ <li className="tiktok__action">
534
+ <button type="button" className="tiktok__button" aria-label={label} aria-pressed={pressed} onClick={onClick}>
535
+ {surface === 'desktop' ? <span className="tiktok__puck">{children}</span> : children}
536
+ </button>
537
+ <span className="tiktok__count">{abbreviate(count)}</span>
538
+ </li>
539
+ );
540
+ }
541
+
542
+ export default TikTok;
@@ -0,0 +1,17 @@
1
+ # TikTok - @zyncat/ui/tiktok
2
+
3
+ Group: replicas
4
+ Docs: https://ui.zyncat.app/tiktok
5
+
6
+ A replica of TikTok's post surface: pick surface="desktop" for the 1584x912 web player with the photo carousel, or surface="mobile" for the 452x822 mobile-web viewport.
7
+
8
+ Platform metrics are pinned constants - no token, no --tiktok-* knob, so theming cannot move them.
9
+ name, caption, location (desktop) or music + sound (mobile), likes, comments, saves, shares. slides
10
+ takes an array for the desktop carousel, with slide/defaultSlide/onSlideChange controlling the page;
11
+ ratio letterboxes inside the frame. Chevrons, drag and arrow keys page it; muted, liked, saved,
12
+ followed are controllable toggles; onAction reports comment, share, menu, search. Counts print exact
13
+ below 10,000 then abbreviate. No autoplay, no fetch, no wordmark.
14
+
15
+ ```tsx
16
+ <TikTok surface="desktop" name="Lena" caption="coast road" slides={[a, b]} likes={3149} />
17
+ ```