@tcn/ui 0.13.1 → 0.15.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 (336) hide show
  1. package/README.md +1 -1
  2. package/dist/{Color-6BZIO3FS-C9xkPWgz.js → Color-6BZIO3FS-CKNkzBV6.js} +2 -2
  3. package/dist/{Color-6BZIO3FS-C9xkPWgz.js.map → Color-6BZIO3FS-CKNkzBV6.js.map} +1 -1
  4. package/dist/{WithTooltip-65CFNBJE-DEnh547F.js → WithTooltip-65CFNBJE-Bgt57Jw2.js} +2 -2
  5. package/dist/WithTooltip-65CFNBJE-Bgt57Jw2.js.map +1 -0
  6. package/dist/actions/__docs__/components/showcase.js +1 -1
  7. package/dist/actions/button/button_group/button_group.d.ts +1 -0
  8. package/dist/actions/button/button_group/button_group.d.ts.map +1 -1
  9. package/dist/actions/button/button_group/button_group.js +33 -30
  10. package/dist/actions/button/button_group/button_group.js.map +1 -1
  11. package/dist/actions/types.js +2 -0
  12. package/dist/actions/types.js.map +1 -0
  13. package/dist/aside.css +1 -1
  14. package/dist/containers.css +1 -0
  15. package/dist/containers.module-DlGySre0.js +5 -0
  16. package/dist/containers.module-DlGySre0.js.map +1 -0
  17. package/dist/floating_action_button.css +1 -0
  18. package/dist/form/field/common/types.js +2 -0
  19. package/dist/form/field/common/types.js.map +1 -0
  20. package/dist/form/field_set/field_set.d.ts.map +1 -1
  21. package/dist/form/field_set/field_set.js +11 -11
  22. package/dist/form/field_set/field_set.js.map +1 -1
  23. package/dist/formatter-EIJCOSYU-ByaSCvt6.js +6 -0
  24. package/dist/formatter-EIJCOSYU-ByaSCvt6.js.map +1 -0
  25. package/dist/inputs/mask_input/mask_config.js +2 -0
  26. package/dist/inputs/mask_input/mask_config.js.map +1 -0
  27. package/dist/inputs/mask_input/mask_cursor.js +2 -0
  28. package/dist/inputs/mask_input/mask_cursor.js.map +1 -0
  29. package/dist/inputs/multiselect/multiselect_inline_values.js +9 -7
  30. package/dist/inputs/multiselect/multiselect_inline_values.js.map +1 -1
  31. package/dist/inputs/multiselect/multiselect_values.js +4 -2
  32. package/dist/inputs/multiselect/multiselect_values.js.map +1 -1
  33. package/dist/layouts/containers/rail.d.ts.map +1 -0
  34. package/dist/layouts/containers/rail.js +67 -0
  35. package/dist/layouts/containers/rail.js.map +1 -0
  36. package/dist/layouts/containers/scaffold.d.ts.map +1 -0
  37. package/dist/layouts/containers/scaffold.js +67 -0
  38. package/dist/layouts/containers/scaffold.js.map +1 -0
  39. package/dist/layouts/containers/side/side.d.ts.map +1 -0
  40. package/dist/layouts/containers/side/side.js +22 -0
  41. package/dist/layouts/containers/side/side.js.map +1 -0
  42. package/dist/layouts/containers/utility_strip/utility_strip.d.ts.map +1 -0
  43. package/dist/layouts/{rail → containers}/utility_strip/utility_strip.js +5 -5
  44. package/dist/layouts/containers/utility_strip/utility_strip.js.map +1 -0
  45. package/dist/layouts/index.d.ts +5 -8
  46. package/dist/layouts/index.d.ts.map +1 -1
  47. package/dist/layouts/index.js +36 -38
  48. package/dist/layouts/index.js.map +1 -1
  49. package/dist/layouts/section/detail.d.ts +4 -0
  50. package/dist/layouts/section/detail.d.ts.map +1 -0
  51. package/dist/layouts/section/detail.js +11 -0
  52. package/dist/layouts/section/detail.js.map +1 -0
  53. package/dist/layouts/section/heading.js +1 -1
  54. package/dist/layouts/section/index.d.ts +4 -0
  55. package/dist/layouts/section/index.d.ts.map +1 -0
  56. package/dist/layouts/section/index.js +9 -0
  57. package/dist/layouts/section/index.js.map +1 -0
  58. package/dist/layouts/section/section.js +1 -1
  59. package/dist/mobile/actions/button/mobile_button.d.ts +6 -0
  60. package/dist/mobile/actions/button/mobile_button.d.ts.map +1 -0
  61. package/dist/mobile/actions/button/mobile_button.js +21 -0
  62. package/dist/mobile/actions/button/mobile_button.js.map +1 -0
  63. package/dist/mobile/actions/floating_action_button/floating_action_button.d.ts +6 -0
  64. package/dist/mobile/actions/floating_action_button/floating_action_button.d.ts.map +1 -0
  65. package/dist/mobile/actions/floating_action_button/floating_action_button.js +20 -0
  66. package/dist/mobile/actions/floating_action_button/floating_action_button.js.map +1 -0
  67. package/dist/mobile/inputs/date_picker/mobile_date_picker.d.ts +17 -0
  68. package/dist/mobile/inputs/date_picker/mobile_date_picker.d.ts.map +1 -0
  69. package/dist/mobile/inputs/date_picker/mobile_date_picker.js +80 -0
  70. package/dist/mobile/inputs/date_picker/mobile_date_picker.js.map +1 -0
  71. package/dist/mobile/inputs/date_picker/mobile_date_picker_body.d.ts +7 -0
  72. package/dist/mobile/inputs/date_picker/mobile_date_picker_body.d.ts.map +1 -0
  73. package/dist/mobile/inputs/date_picker/mobile_date_picker_body.js +35 -0
  74. package/dist/mobile/inputs/date_picker/mobile_date_picker_body.js.map +1 -0
  75. package/dist/mobile/inputs/date_picker/mobile_date_picker_date.d.ts +8 -0
  76. package/dist/mobile/inputs/date_picker/mobile_date_picker_date.d.ts.map +1 -0
  77. package/dist/mobile/inputs/date_picker/mobile_date_picker_date.js +74 -0
  78. package/dist/mobile/inputs/date_picker/mobile_date_picker_date.js.map +1 -0
  79. package/dist/mobile/inputs/date_picker/mobile_date_picker_day.d.ts +6 -0
  80. package/dist/mobile/inputs/date_picker/mobile_date_picker_day.d.ts.map +1 -0
  81. package/dist/mobile/inputs/date_picker/mobile_date_picker_day.js +39 -0
  82. package/dist/mobile/inputs/date_picker/mobile_date_picker_day.js.map +1 -0
  83. package/dist/mobile/inputs/date_picker/mobile_date_picker_header.d.ts +9 -0
  84. package/dist/mobile/inputs/date_picker/mobile_date_picker_header.d.ts.map +1 -0
  85. package/dist/mobile/inputs/date_picker/mobile_date_picker_header.js +163 -0
  86. package/dist/mobile/inputs/date_picker/mobile_date_picker_header.js.map +1 -0
  87. package/dist/mobile/inputs/date_picker/mobile_date_picker_input.d.ts +9 -0
  88. package/dist/mobile/inputs/date_picker/mobile_date_picker_input.d.ts.map +1 -0
  89. package/dist/mobile/inputs/date_picker/mobile_date_picker_input.js +190 -0
  90. package/dist/mobile/inputs/date_picker/mobile_date_picker_input.js.map +1 -0
  91. package/dist/mobile/inputs/date_picker/mobile_date_picker_time_selector.d.ts +11 -0
  92. package/dist/mobile/inputs/date_picker/mobile_date_picker_time_selector.d.ts.map +1 -0
  93. package/dist/mobile/inputs/date_picker/mobile_date_picker_time_selector.js +50 -0
  94. package/dist/mobile/inputs/date_picker/mobile_date_picker_time_selector.js.map +1 -0
  95. package/dist/mobile/inputs/date_picker/mobile_date_picker_year_selector.d.ts +7 -0
  96. package/dist/mobile/inputs/date_picker/mobile_date_picker_year_selector.d.ts.map +1 -0
  97. package/dist/mobile/inputs/date_picker/mobile_date_picker_year_selector.js +109 -0
  98. package/dist/mobile/inputs/date_picker/mobile_date_picker_year_selector.js.map +1 -0
  99. package/dist/mobile/inputs/date_picker/mobile_overlay_header.d.ts +6 -0
  100. package/dist/mobile/inputs/date_picker/mobile_overlay_header.d.ts.map +1 -0
  101. package/dist/mobile/inputs/date_picker/mobile_overlay_header.js +34 -0
  102. package/dist/mobile/inputs/date_picker/mobile_overlay_header.js.map +1 -0
  103. package/dist/mobile/inputs/index.d.ts +5 -0
  104. package/dist/mobile/inputs/index.d.ts.map +1 -0
  105. package/dist/mobile/inputs/index.js +11 -0
  106. package/dist/mobile/inputs/index.js.map +1 -0
  107. package/dist/mobile/portal/mobile_portal.d.ts +5 -0
  108. package/dist/mobile/portal/mobile_portal.d.ts.map +1 -0
  109. package/dist/mobile/portal/mobile_portal.js +10 -0
  110. package/dist/mobile/portal/mobile_portal.js.map +1 -0
  111. package/dist/mobile/viewport/mobile_viewport.d.ts +21 -0
  112. package/dist/mobile/viewport/mobile_viewport.d.ts.map +1 -0
  113. package/dist/mobile/viewport/mobile_viewport.js +31 -0
  114. package/dist/mobile/viewport/mobile_viewport.js.map +1 -0
  115. package/dist/mobile_button.css +1 -0
  116. package/dist/mobile_date_picker.css +1 -0
  117. package/dist/mobile_date_picker_date.css +1 -0
  118. package/dist/mobile_date_picker_day.css +1 -0
  119. package/dist/mobile_date_picker_header.css +1 -0
  120. package/dist/mobile_date_picker_input.css +1 -0
  121. package/dist/mobile_date_picker_time_selector.css +1 -0
  122. package/dist/mobile_date_picker_year_selector.css +1 -0
  123. package/dist/mobile_overlay_header.css +1 -0
  124. package/dist/mobile_viewport.css +1 -0
  125. package/dist/navigation/tabs/state/link/use_tab_link.d.ts +2 -1
  126. package/dist/navigation/tabs/state/link/use_tab_link.d.ts.map +1 -1
  127. package/dist/navigation/tabs/state/link/use_tab_link.js.map +1 -1
  128. package/dist/overlay/tethered/types.js +2 -0
  129. package/dist/overlay/tethered/types.js.map +1 -0
  130. package/dist/panel.css +1 -1
  131. package/dist/phone_number_input.css +1 -1
  132. package/dist/section.css +1 -1
  133. package/dist/section.module-BXlxYmJK.js +5 -0
  134. package/dist/section.module-BXlxYmJK.js.map +1 -0
  135. package/dist/{showcase-y9D3_Y8T.js → showcase-DBFp_Epk.js} +94 -94
  136. package/dist/showcase-DBFp_Epk.js.map +1 -0
  137. package/dist/side.css +1 -1
  138. package/dist/stacks/box/handle_props.js +2 -0
  139. package/dist/stacks/box/handle_props.js.map +1 -0
  140. package/dist/stacks/box/types.js +2 -0
  141. package/dist/stacks/box/types.js.map +1 -0
  142. package/dist/surfaces/aside/aside.d.ts +1 -1
  143. package/dist/surfaces/aside/aside.d.ts.map +1 -1
  144. package/dist/surfaces/aside/aside.js +1 -1
  145. package/dist/surfaces/aside/aside.js.map +1 -1
  146. package/dist/surfaces/card/card.d.ts +1 -1
  147. package/dist/surfaces/card/card.d.ts.map +1 -1
  148. package/dist/surfaces/card/card.js +1 -1
  149. package/dist/surfaces/card/card.js.map +1 -1
  150. package/dist/surfaces/drawers/drawer.js +1 -1
  151. package/dist/surfaces/drawers/drawer.js.map +1 -1
  152. package/dist/surfaces/modal/modal.js +1 -1
  153. package/dist/surfaces/modal/modal.js.map +1 -1
  154. package/dist/surfaces/page/page.d.ts +1 -1
  155. package/dist/surfaces/page/page.d.ts.map +1 -1
  156. package/dist/surfaces/page/page.js +1 -1
  157. package/dist/surfaces/page/page.js.map +1 -1
  158. package/dist/surfaces/panel/panel.d.ts +1 -1
  159. package/dist/surfaces/panel/panel.d.ts.map +1 -1
  160. package/dist/surfaces/panel/panel.js +1 -1
  161. package/dist/surfaces/panel/panel.js.map +1 -1
  162. package/dist/surfaces/pop_confirm/pop_confirm.js +8 -9
  163. package/dist/surfaces/pop_confirm/pop_confirm.js.map +1 -1
  164. package/dist/surfaces/window/window.js +1 -1
  165. package/dist/surfaces/window/window.js.map +1 -1
  166. package/dist/{syntaxhighlighter-ED5Y7EFY-CqInEOwQ.js → syntaxhighlighter-ED5Y7EFY-B0ag_7lq.js} +2 -2
  167. package/dist/syntaxhighlighter-ED5Y7EFY-B0ag_7lq.js.map +1 -0
  168. package/dist/term.css +1 -0
  169. package/dist/themes/build_stylesheet.d.ts +2 -0
  170. package/dist/themes/build_stylesheet.d.ts.map +1 -0
  171. package/dist/themes/build_stylesheet.js +9 -0
  172. package/dist/themes/build_stylesheet.js.map +1 -0
  173. package/dist/themes/theme_variables.d.ts +7 -0
  174. package/dist/themes/theme_variables.d.ts.map +1 -1
  175. package/dist/themes/theme_variables.js +16 -9
  176. package/dist/themes/theme_variables.js.map +1 -1
  177. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  178. package/dist/themes/themes/ergo/ergo_theme.d.ts.map +1 -1
  179. package/dist/themes/themes/ergo/ergo_theme.js +314 -154
  180. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  181. package/dist/themes/themes/ergo/tokens/system_tokens.css +1 -0
  182. package/dist/themes/themes/ergo/tokens/theme_tokens.css +1 -0
  183. package/dist/tokens/index.d.ts +1 -0
  184. package/dist/tokens/index.d.ts.map +1 -1
  185. package/dist/tokens/index.js +4 -2
  186. package/dist/tokens/index.js.map +1 -1
  187. package/dist/tokens/key/key.d.ts +8 -1
  188. package/dist/tokens/key/key.d.ts.map +1 -1
  189. package/dist/tokens/key/key.js +20 -3
  190. package/dist/tokens/key/key.js.map +1 -1
  191. package/dist/tokens/term/term.d.ts +4 -0
  192. package/dist/tokens/term/term.d.ts.map +1 -0
  193. package/dist/tokens/term/term.js +20 -0
  194. package/dist/tokens/term/term.js.map +1 -0
  195. package/dist/tokens/value/value.d.ts +8 -1
  196. package/dist/tokens/value/value.d.ts.map +1 -1
  197. package/dist/tokens/value/value.js +23 -5
  198. package/dist/tokens/value/value.js.map +1 -1
  199. package/dist/utility_strip.css +1 -1
  200. package/dist/utils/calendar/calendar_date.js +2 -0
  201. package/dist/utils/calendar/calendar_date.js.map +1 -0
  202. package/dist/utils/dnd/types.js +2 -0
  203. package/dist/utils/dnd/types.js.map +1 -0
  204. package/dist/utils/types/variations.d.ts +1 -0
  205. package/dist/utils/types/variations.d.ts.map +1 -1
  206. package/dist/value.css +1 -0
  207. package/dist/value.module-DFaCouFD.js +5 -0
  208. package/dist/value.module-DFaCouFD.js.map +1 -0
  209. package/package.json +17 -16
  210. package/src/actions/button/button_group/button_group.tsx +18 -10
  211. package/src/form/field_set/field_set.tsx +4 -2
  212. package/src/inputs/phone_number_input/phone_number_input.module.css +7 -5
  213. package/src/layouts/__stories__/composed.stories.tsx +13 -8
  214. package/src/layouts/__stories__/composed_stories.module.css +1 -0
  215. package/src/layouts/__stories__/rail.stories.tsx +23 -25
  216. package/src/layouts/__stories__/scaffold.stories.tsx +21 -41
  217. package/src/layouts/__stories__/utils/layout_theme.css +0 -4
  218. package/src/layouts/__stories__/utils/layout_theme_provider.tsx +8 -1
  219. package/src/layouts/__stories__/utils.tsx +15 -29
  220. package/src/layouts/containers/containers.module.css +55 -0
  221. package/src/layouts/{rail → containers}/rail.tsx +15 -5
  222. package/src/layouts/{scaffold → containers}/scaffold.tsx +15 -5
  223. package/src/layouts/{rail → containers}/side/side.tsx +2 -1
  224. package/src/layouts/index.ts +6 -8
  225. package/src/layouts/section/__stories__/section.stories.tsx +79 -50
  226. package/src/layouts/section/detail.tsx +14 -0
  227. package/src/layouts/section/index.ts +3 -0
  228. package/src/layouts/section/section.module.css +0 -36
  229. package/src/mobile/actions/button/mobile_button.module.css +34 -0
  230. package/src/mobile/actions/button/mobile_button.stories.tsx +97 -0
  231. package/src/mobile/actions/button/mobile_button.tsx +26 -0
  232. package/src/mobile/actions/floating_action_button/floating_action_button.module.css +28 -0
  233. package/src/mobile/actions/floating_action_button/floating_action_button.stories.tsx +102 -0
  234. package/src/mobile/actions/floating_action_button/floating_action_button.tsx +25 -0
  235. package/src/mobile/inputs/date_picker/mobile_date_picker.module.css +22 -0
  236. package/src/mobile/inputs/date_picker/mobile_date_picker.tsx +118 -0
  237. package/src/mobile/inputs/date_picker/mobile_date_picker_body.tsx +57 -0
  238. package/src/mobile/inputs/date_picker/mobile_date_picker_date.module.css +80 -0
  239. package/src/mobile/inputs/date_picker/mobile_date_picker_date.tsx +102 -0
  240. package/src/mobile/inputs/date_picker/mobile_date_picker_day.module.css +6 -0
  241. package/src/mobile/inputs/date_picker/mobile_date_picker_day.tsx +40 -0
  242. package/src/mobile/inputs/date_picker/mobile_date_picker_header.module.css +21 -0
  243. package/src/mobile/inputs/date_picker/mobile_date_picker_header.tsx +180 -0
  244. package/src/mobile/inputs/date_picker/mobile_date_picker_input.module.css +13 -0
  245. package/src/mobile/inputs/date_picker/mobile_date_picker_input.stories.tsx +27 -0
  246. package/src/mobile/inputs/date_picker/mobile_date_picker_input.tsx +240 -0
  247. package/src/mobile/inputs/date_picker/mobile_date_picker_time_selector.module.css +7 -0
  248. package/src/mobile/inputs/date_picker/mobile_date_picker_time_selector.tsx +81 -0
  249. package/src/mobile/inputs/date_picker/mobile_date_picker_year_selector.module.css +55 -0
  250. package/src/mobile/inputs/date_picker/mobile_date_picker_year_selector.tsx +119 -0
  251. package/src/mobile/inputs/date_picker/mobile_overlay_header.module.css +5 -0
  252. package/src/mobile/inputs/date_picker/mobile_overlay_header.tsx +29 -0
  253. package/src/mobile/inputs/index.ts +4 -0
  254. package/src/mobile/portal/mobile_portal.tsx +14 -0
  255. package/src/mobile/viewport/mobile_viewport.module.css +23 -0
  256. package/src/mobile/viewport/mobile_viewport.tsx +80 -0
  257. package/src/navigation/tabs/state/link/use_tab_link.ts +1 -1
  258. package/src/overlay/slide/slide.stories.tsx +6 -9
  259. package/src/surfaces/aside/aside.module.css +1 -0
  260. package/src/surfaces/aside/aside.stories.tsx +24 -38
  261. package/src/surfaces/aside/aside.tsx +1 -1
  262. package/src/surfaces/card/card.stories.tsx +5 -7
  263. package/src/surfaces/card/card.tsx +1 -1
  264. package/src/surfaces/drawers/drawer.stories.tsx +10 -13
  265. package/src/surfaces/drawers/drawer.tsx +1 -1
  266. package/src/surfaces/modal/__stories__/modal.stories.tsx +10 -13
  267. package/src/surfaces/modal/modal.tsx +1 -1
  268. package/src/surfaces/page/page.stories.tsx +28 -32
  269. package/src/surfaces/page/page.tsx +1 -1
  270. package/src/surfaces/panel/__stories__/panel.stories.tsx +199 -66
  271. package/src/surfaces/panel/panel.module.css +1 -1
  272. package/src/surfaces/panel/panel.tsx +1 -1
  273. package/src/surfaces/pop_confirm/pop_confirm.stories.tsx +29 -37
  274. package/src/surfaces/tooltip/__stories__/tooltip.stories.tsx +8 -10
  275. package/src/surfaces/window/window.stories.tsx +6 -15
  276. package/src/surfaces/window/window.tsx +1 -1
  277. package/src/themes/build_stylesheet.ts +5 -0
  278. package/src/themes/theme_variables.ts +9 -0
  279. package/src/themes/themes/ergo/__stories__/components/tone_picker/sb_tone_card.tsx +6 -8
  280. package/src/themes/themes/ergo/__stories__/material.stories.tsx +4 -6
  281. package/src/themes/themes/ergo/ergo_theme.css +208 -215
  282. package/src/themes/themes/ergo/ergo_theme.ts +4 -2
  283. package/src/themes/themes/ergo/tokens/system_tokens.css +68 -0
  284. package/src/themes/themes/ergo/tokens/theme_tokens.css +99 -0
  285. package/src/tokens/index.ts +1 -0
  286. package/src/tokens/key/key.tsx +23 -2
  287. package/src/tokens/term/term.module.css +14 -0
  288. package/src/tokens/term/term.stories.tsx +84 -0
  289. package/src/tokens/term/term.tsx +20 -0
  290. package/src/tokens/value/value.module.css +5 -0
  291. package/src/tokens/value/value.tsx +24 -2
  292. package/src/utils/types/variations.ts +1 -0
  293. package/tsconfig.json +5 -33
  294. package/dist/WithTooltip-65CFNBJE-DEnh547F.js.map +0 -1
  295. package/dist/body.css +0 -1
  296. package/dist/formatter-EIJCOSYU-DWmgEY3b.js +0 -6
  297. package/dist/formatter-EIJCOSYU-DWmgEY3b.js.map +0 -1
  298. package/dist/layouts/body/body.d.ts +0 -23
  299. package/dist/layouts/body/body.d.ts.map +0 -1
  300. package/dist/layouts/body/body.js +0 -20
  301. package/dist/layouts/body/body.js.map +0 -1
  302. package/dist/layouts/rail/rail.d.ts.map +0 -1
  303. package/dist/layouts/rail/rail.js +0 -55
  304. package/dist/layouts/rail/rail.js.map +0 -1
  305. package/dist/layouts/rail/side/side.d.ts.map +0 -1
  306. package/dist/layouts/rail/side/side.js +0 -21
  307. package/dist/layouts/rail/side/side.js.map +0 -1
  308. package/dist/layouts/rail/utility_strip/utility_strip.d.ts.map +0 -1
  309. package/dist/layouts/rail/utility_strip/utility_strip.js.map +0 -1
  310. package/dist/layouts/row/row.d.ts +0 -4
  311. package/dist/layouts/row/row.d.ts.map +0 -1
  312. package/dist/layouts/row/row.js +0 -11
  313. package/dist/layouts/row/row.js.map +0 -1
  314. package/dist/layouts/scaffold/scaffold.d.ts.map +0 -1
  315. package/dist/layouts/scaffold/scaffold.js +0 -55
  316. package/dist/layouts/scaffold/scaffold.js.map +0 -1
  317. package/dist/rail.css +0 -1
  318. package/dist/row.css +0 -1
  319. package/dist/scaffold.css +0 -1
  320. package/dist/section.module-0wyGkhDg.js +0 -5
  321. package/dist/section.module-0wyGkhDg.js.map +0 -1
  322. package/dist/showcase-y9D3_Y8T.js.map +0 -1
  323. package/dist/syntaxhighlighter-ED5Y7EFY-CqInEOwQ.js.map +0 -1
  324. package/src/layouts/body/body.module.css +0 -8
  325. package/src/layouts/body/body.tsx +0 -40
  326. package/src/layouts/rail/rail.module.css +0 -14
  327. package/src/layouts/row/row.module.css +0 -5
  328. package/src/layouts/row/row.tsx +0 -15
  329. package/src/layouts/scaffold/scaffold.module.css +0 -14
  330. /package/dist/layouts/{rail → containers}/rail.d.ts +0 -0
  331. /package/dist/layouts/{scaffold → containers}/scaffold.d.ts +0 -0
  332. /package/dist/layouts/{rail → containers}/side/side.d.ts +0 -0
  333. /package/dist/layouts/{rail → containers}/utility_strip/utility_strip.d.ts +0 -0
  334. /package/src/layouts/{rail → containers}/side/side.module.css +0 -0
  335. /package/src/layouts/{rail → containers}/utility_strip/utility_strip.module.css +0 -0
  336. /package/src/layouts/{rail → containers}/utility_strip/utility_strip.tsx +0 -0
@@ -0,0 +1,240 @@
1
+ import React, { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
2
+ import { MobileButton } from '../../actions/button/mobile_button.js';
3
+ import { ButtonGroup } from '../../../actions/button/button_group/button_group.js';
4
+ import { MobilePortal } from '../../portal/mobile_portal.js';
5
+ import { MobileDatePicker } from './mobile_date_picker.js';
6
+ import { MobileDatePickerTimeSelector } from './mobile_date_picker_time_selector.js';
7
+ import { MobileOverlayHeader } from './mobile_overlay_header.js';
8
+ import { FocusRedirect } from '../../../utils/index.js';
9
+ import { VStack } from '../../../stacks/v_stack.js';
10
+ import type { DatePickerInputProps } from '../../../inputs/date_picker/date_picker_input.js';
11
+ import styles from './mobile_date_picker_input.module.css';
12
+
13
+ export interface MobileDatePickerInputProps extends DatePickerInputProps {
14
+ selectTimeMessage?: string;
15
+ selectMonthMessage?: string;
16
+ selectYearMessage?: string;
17
+ }
18
+
19
+ export const MobileDatePickerInput = React.forwardRef<
20
+ HTMLButtonElement,
21
+ MobileDatePickerInputProps
22
+ >(function MobileDatePickerInput(
23
+ {
24
+ value = new Date(),
25
+ onChange,
26
+ onError,
27
+ min = new Date('01/01/1924'),
28
+ max = new Date('01/01/2124'),
29
+ disabled,
30
+ width = '100%',
31
+ maxWidth,
32
+ minWidth,
33
+ showTime = false,
34
+ timeIntervalInMinutes = 15,
35
+ hierarchy = 'secondary',
36
+ disabledDates,
37
+ selectDateMessage = 'Select Date',
38
+ selectTimeMessage = 'Select Time',
39
+ selectMonthMessage,
40
+ selectYearMessage,
41
+ countryCode,
42
+ renderActions,
43
+ onTimeSelected,
44
+ ...props
45
+ },
46
+ ref
47
+ ) {
48
+ const [dateOpen, setDateOpen] = useState(false);
49
+ const [timeOpen, setTimeOpen] = useState(false);
50
+ const pickerRef = useRef<HTMLDivElement | null>(null);
51
+ const timeRef = useRef<HTMLDivElement | null>(null);
52
+ const dateButtonRef = useRef<HTMLButtonElement | null>(null);
53
+ const timeButtonRef = useRef<HTMLButtonElement | null>(null);
54
+
55
+ const setDateButtonRef = useCallback(
56
+ (node: HTMLButtonElement | null) => {
57
+ dateButtonRef.current = node;
58
+ if (typeof ref === 'function') {
59
+ ref(node);
60
+ } else if (ref != null) {
61
+ (ref as React.MutableRefObject<HTMLButtonElement | null>).current = node;
62
+ }
63
+ },
64
+ [ref]
65
+ );
66
+
67
+ const dateFormatter = useMemo(() => {
68
+ return new Intl.DateTimeFormat(countryCode, {
69
+ year: 'numeric',
70
+ month: 'short',
71
+ day: 'numeric',
72
+ });
73
+ }, [countryCode]);
74
+
75
+ const timeFormatter = useMemo(() => {
76
+ return new Intl.DateTimeFormat(countryCode, {
77
+ hour: 'numeric',
78
+ minute: '2-digit',
79
+ hour12: true,
80
+ });
81
+ }, [countryCode]);
82
+
83
+ const formattedDate = value != null ? dateFormatter.format(value) : selectDateMessage;
84
+ const formattedTime = value != null ? timeFormatter.format(value) : selectTimeMessage;
85
+
86
+ function openDatePicker() {
87
+ setDateOpen(true);
88
+ }
89
+
90
+ function closeDatePicker() {
91
+ setDateOpen(false);
92
+ requestAnimationFrame(() => dateButtonRef.current?.focus());
93
+ }
94
+
95
+ function openTimePicker() {
96
+ setTimeOpen(true);
97
+ }
98
+
99
+ function closeTimePicker() {
100
+ setTimeOpen(false);
101
+ requestAnimationFrame(() => timeButtonRef.current?.focus());
102
+ }
103
+
104
+ useLayoutEffect(() => {
105
+ if (dateOpen) {
106
+ requestAnimationFrame(() => pickerRef.current?.focus());
107
+ }
108
+ }, [dateOpen]);
109
+
110
+ useLayoutEffect(() => {
111
+ if (timeOpen) {
112
+ requestAnimationFrame(() => timeRef.current?.focus());
113
+ }
114
+ }, [timeOpen]);
115
+
116
+ function handleDateEscape(event: React.KeyboardEvent) {
117
+ if (event.key === 'Escape') {
118
+ closeDatePicker();
119
+ }
120
+ }
121
+
122
+ function handleTimeEscape(event: React.KeyboardEvent) {
123
+ if (event.key === 'Escape') {
124
+ closeTimePicker();
125
+ }
126
+ }
127
+
128
+ function handleDateRedirect() {
129
+ pickerRef.current?.focus();
130
+ }
131
+
132
+ function handleTimeRedirect() {
133
+ timeRef.current?.focus();
134
+ }
135
+
136
+ function dateSelected(date: Date | null) {
137
+ onChange?.(date);
138
+ closeDatePicker();
139
+ }
140
+
141
+ function timeSelected(hour: number, minutes: number, seconds: number) {
142
+ if (value != null) {
143
+ const updated = new Date(value);
144
+ updated.setHours(hour, minutes, seconds);
145
+ onChange?.(updated);
146
+ }
147
+ onTimeSelected?.(hour, minutes, seconds);
148
+ closeTimePicker();
149
+ }
150
+
151
+ return (
152
+ <>
153
+ {showTime ? (
154
+ <ButtonGroup hierarchy={hierarchy} width={width}>
155
+ <MobileButton
156
+ ref={setDateButtonRef}
157
+ hAlign="start"
158
+ disabled={disabled}
159
+ onClick={openDatePicker}
160
+ width="flex"
161
+ {...props}
162
+ >
163
+ <span className="ellipsis">{formattedDate}</span>
164
+ </MobileButton>
165
+ <MobileButton
166
+ ref={timeButtonRef}
167
+ hAlign="start"
168
+ disabled={disabled || value == null}
169
+ onClick={openTimePicker}
170
+ width="auto"
171
+ >
172
+ <span className="ellipsis">{formattedTime}</span>
173
+ </MobileButton>
174
+ </ButtonGroup>
175
+ ) : (
176
+ <MobileButton
177
+ ref={setDateButtonRef}
178
+ hAlign="start"
179
+ disabled={disabled}
180
+ hierarchy={hierarchy}
181
+ onClick={openDatePicker}
182
+ width={width}
183
+ maxWidth={maxWidth}
184
+ {...props}
185
+ >
186
+ <span className="ellipsis">{formattedDate}</span>
187
+ </MobileButton>
188
+ )}
189
+
190
+ {dateOpen && (
191
+ <MobilePortal>
192
+ <VStack
193
+ className={styles['mobile-date-picker-overlay']}
194
+ onKeyDown={handleDateEscape}
195
+ >
196
+ <MobileOverlayHeader title={selectDateMessage} onClose={closeDatePicker} />
197
+ <MobileDatePicker
198
+ ref={pickerRef}
199
+ value={value}
200
+ onChange={dateSelected}
201
+ min={min}
202
+ max={max}
203
+ onError={onError}
204
+ disabled={disabled}
205
+ disabledDates={disabledDates}
206
+ countryCode={countryCode}
207
+ renderActions={renderActions}
208
+ selectMonthMessage={selectMonthMessage}
209
+ selectYearMessage={selectYearMessage}
210
+ />
211
+ <FocusRedirect onRedirect={handleDateRedirect} />
212
+ </VStack>
213
+ </MobilePortal>
214
+ )}
215
+
216
+ {timeOpen && (
217
+ <MobilePortal>
218
+ <VStack
219
+ className={styles['mobile-time-picker-overlay']}
220
+ onKeyDown={handleTimeEscape}
221
+ >
222
+ <MobileOverlayHeader title={selectTimeMessage} onClose={closeTimePicker} />
223
+ <MobileDatePickerTimeSelector
224
+ ref={timeRef}
225
+ origin={value}
226
+ min={min}
227
+ max={max}
228
+ intervalInMinutes={timeIntervalInMinutes}
229
+ disabled={disabled}
230
+ onSelect={(hour, minutes, seconds) => {
231
+ timeSelected(hour, minutes, seconds);
232
+ }}
233
+ />
234
+ <FocusRedirect onRedirect={handleTimeRedirect} />
235
+ </VStack>
236
+ </MobilePortal>
237
+ )}
238
+ </>
239
+ );
240
+ });
@@ -0,0 +1,7 @@
1
+ @layer tcn-system {
2
+ :where(.mobile-time-selector) {
3
+ outline: none;
4
+ background-color: var(--surface-color, #fff);
5
+ color: var(--font-color);
6
+ }
7
+ }
@@ -0,0 +1,81 @@
1
+ import { VStack } from '../../../stacks/v_stack.js';
2
+ import { clsx } from 'clsx';
3
+ import React from 'react';
4
+ import { MobileButton } from '../../actions/button/mobile_button.js';
5
+ import styles from './mobile_date_picker_time_selector.module.css';
6
+
7
+ export interface MobileDatePickerTimeSelectorProps {
8
+ origin: Date | null;
9
+ intervalInMinutes: number;
10
+ max: Date | null;
11
+ min: Date | null;
12
+ onSelect: (hours: number, minutes: number, seconds: number) => void;
13
+ disabled?: boolean;
14
+ }
15
+
16
+ export const MobileDatePickerTimeSelector = React.forwardRef<
17
+ HTMLDivElement,
18
+ MobileDatePickerTimeSelectorProps
19
+ >(function MobileDatePickerTimeSelector(
20
+ { origin, intervalInMinutes, max, min, onSelect, disabled },
21
+ ref
22
+ ) {
23
+ const stepInMilliseconds = intervalInMinutes * 1000 * 60;
24
+ const amountOfSteps = (24 * 1000 * 60 * 60) / stepInMilliseconds;
25
+ const normalizedDate = new Date(origin || new Date());
26
+ const options: React.ReactElement[] = [];
27
+ const minTime = min?.getTime() ?? -Infinity;
28
+ const maxTime = max?.getTime() ?? Infinity;
29
+
30
+ normalizedDate.setHours(0, 0, 0, 0);
31
+ let offset = normalizedDate.getTime();
32
+
33
+ for (let x = 0; x < amountOfSteps; x++) {
34
+ const date = new Date(offset);
35
+
36
+ let hour = date.getHours() % 12;
37
+ const minute = date.getMinutes();
38
+ const meridiem = date.getHours() >= 12 ? 'PM' : 'AM';
39
+ hour = hour === 0 ? 12 : hour;
40
+
41
+ const isSelected =
42
+ origin != null &&
43
+ date.getHours() === origin.getHours() &&
44
+ date.getMinutes() === origin.getMinutes() &&
45
+ date.getSeconds() === origin.getSeconds();
46
+
47
+ const time = date.getTime();
48
+ const isOutOfRange = time < minTime || time > maxTime;
49
+
50
+ options.push(
51
+ <MobileButton
52
+ key={x}
53
+ width="100%"
54
+ hierarchy={isSelected ? 'primary' : 'tertiary'}
55
+ disabled={origin == null || disabled || isOutOfRange}
56
+ onClick={() => {
57
+ onSelect(date.getHours(), date.getMinutes(), date.getSeconds());
58
+ }}
59
+ >
60
+ {`${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')} ${meridiem}`}
61
+ </MobileButton>
62
+ );
63
+
64
+ offset += stepInMilliseconds;
65
+ }
66
+
67
+ return (
68
+ <VStack
69
+ ref={ref}
70
+ tabIndex={0}
71
+ width="100%"
72
+ height="flex"
73
+ overflowY="auto"
74
+ padding="8px"
75
+ gap="4px"
76
+ className={clsx(styles['mobile-time-selector'], 'tcn-mobile-time-selector')}
77
+ >
78
+ {options}
79
+ </VStack>
80
+ );
81
+ });
@@ -0,0 +1,55 @@
1
+ @layer tcn-system {
2
+ :where(.mobile-year-selector) {
3
+ background-color: var(--surface-color, #fff);
4
+ outline: none;
5
+ }
6
+
7
+ :where(.mobile-year-button) {
8
+ flex: 1 1 0%;
9
+ aspect-ratio: 1.6;
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ padding: 4px;
14
+ border: 2px solid transparent;
15
+ border-radius: 4px;
16
+ cursor: pointer;
17
+ background-color: transparent;
18
+ color: var(--font-color);
19
+ -webkit-tap-highlight-color: transparent;
20
+ -webkit-touch-callout: none;
21
+ touch-action: manipulation;
22
+ -webkit-user-select: none;
23
+ -moz-user-select: none;
24
+ -ms-user-select: none;
25
+ user-select: none;
26
+ -webkit-appearance: none;
27
+ -moz-appearance: none;
28
+ appearance: none;
29
+ outline: none;
30
+ }
31
+
32
+ :where(.mobile-year-button:hover),
33
+ :where(.mobile-year-button:focus) {
34
+ border: 2px dotted var(--accent-color);
35
+ outline: none;
36
+ -webkit-tap-highlight-color: transparent;
37
+ -webkit-touch-callout: none;
38
+ }
39
+
40
+ :where(.mobile-year-button[data-is-selected="true"]) {
41
+ border: 2px solid var(--accent-color);
42
+ background-color: var(--accent-color);
43
+ color: #fff;
44
+ box-shadow: 0 0px 4px rgba(0, 0, 0, 0.35);
45
+ -webkit-tap-highlight-color: transparent;
46
+ -webkit-touch-callout: none;
47
+ }
48
+
49
+ :where(.mobile-year-button[data-is-disabled="true"]) {
50
+ text-decoration: line-through;
51
+ opacity: 0.5;
52
+ border: 2px solid transparent;
53
+ cursor: not-allowed;
54
+ }
55
+ }
@@ -0,0 +1,119 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { ChevronLeftIcon } from '@tcn/icons/chevron_left_icon.js';
3
+ import { ChevronRightIcon } from '@tcn/icons/chevron_right_icon.js';
4
+ import { useSignalValue } from '@tcn/state';
5
+ import { MobileButton } from '../../actions/button/mobile_button.js';
6
+ import { HStack } from '../../../stacks/h_stack.js';
7
+ import { Spacer } from '../../../stacks/spacer.js';
8
+ import { VStack } from '../../../stacks/v_stack.js';
9
+ import { BodyText, Headline } from '../../../typography/index.js';
10
+ import { DatePickerPresenter } from '../../../inputs/date_picker/date_picker_presenter.js';
11
+ import { FocusRedirect } from '../../../utils/index.js';
12
+ import { clsx } from 'clsx';
13
+ import styles from './mobile_date_picker_year_selector.module.css';
14
+
15
+ export interface MobileDatePickerYearSelectorProps {
16
+ presenter: DatePickerPresenter;
17
+ onClose: () => void;
18
+ }
19
+
20
+ export function MobileDatePickerYearSelector({
21
+ presenter,
22
+ onClose,
23
+ }: MobileDatePickerYearSelectorProps) {
24
+ const { min, max, visibleYear, visibleMonth } = useSignalValue(
25
+ presenter.stateBroadcast
26
+ );
27
+
28
+ const [offset, setOffset] = useState(0);
29
+ const containerRef = useRef<HTMLDivElement | null>(null);
30
+ const minYear = min == null ? -Infinity : min.getFullYear();
31
+ const maxYear = max == null ? Infinity : max.getFullYear();
32
+ const years: React.ReactNode[] = [];
33
+ const remainder = visibleYear % 20;
34
+ const firstYear = visibleYear - remainder + offset;
35
+ const lastYear = firstYear + 19;
36
+
37
+ for (let x = 0; x < 20; x++) {
38
+ const date = new Date(visibleYear, visibleMonth, 1);
39
+ date.setFullYear(visibleYear - remainder + x + offset);
40
+
41
+ const disabled = date.getFullYear() > maxYear || date.getFullYear() < minYear;
42
+
43
+ years.push(
44
+ <button
45
+ key={x}
46
+ disabled={disabled}
47
+ className={clsx(styles['mobile-year-button'], 'tcn-date-picker-year-button')}
48
+ data-is-disabled={String(disabled)}
49
+ data-is-selected={String(date.getFullYear() === visibleYear)}
50
+ onClick={() => {
51
+ presenter.setVisibleYear(date.getFullYear());
52
+ onClose();
53
+ }}
54
+ >
55
+ <BodyText>{date.getFullYear()}</BodyText>
56
+ </button>
57
+ );
58
+ }
59
+
60
+ function focus() {
61
+ containerRef.current?.focus();
62
+ }
63
+
64
+ useEffect(() => {
65
+ containerRef.current?.focus();
66
+ }, []);
67
+
68
+ const rows = [
69
+ years.slice(0, 4),
70
+ years.slice(4, 8),
71
+ years.slice(8, 12),
72
+ years.slice(12, 16),
73
+ years.slice(16, 20),
74
+ ];
75
+
76
+ function prev() {
77
+ setOffset(offset - 20);
78
+ }
79
+
80
+ function next() {
81
+ setOffset(offset + 20);
82
+ }
83
+
84
+ return (
85
+ <VStack
86
+ ref={containerRef}
87
+ tabIndex={0}
88
+ padding="8px"
89
+ width="100%"
90
+ className={clsx(
91
+ styles['mobile-year-selector'],
92
+ 'tcn-mobile-date-picker-year-selector'
93
+ )}
94
+ gap="4px"
95
+ >
96
+ <HStack gap="4px">
97
+ <MobileButton onClick={prev} hierarchy="tertiary" width="auto">
98
+ <ChevronLeftIcon flipOnRtl size="md" />
99
+ </MobileButton>
100
+ <Spacer />
101
+ <Headline
102
+ selectable={false}
103
+ emphasis="faint"
104
+ hierarchy="tertiary"
105
+ >{`${firstYear}-${lastYear}`}</Headline>
106
+ <Spacer />
107
+ <MobileButton hierarchy="tertiary" width="auto" onClick={next}>
108
+ <ChevronRightIcon size="md" />
109
+ </MobileButton>
110
+ </HStack>
111
+ {rows.map((row, index) => (
112
+ <HStack key={index} gap="4px" width="100%">
113
+ {row}
114
+ </HStack>
115
+ ))}
116
+ <FocusRedirect onRedirect={focus} />
117
+ </VStack>
118
+ );
119
+ }
@@ -0,0 +1,5 @@
1
+ @layer tcn-system {
2
+ :where(.mobile-overlay-header) {
3
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
4
+ }
5
+ }
@@ -0,0 +1,29 @@
1
+ import { HStack } from '../../../stacks/h_stack.js';
2
+ import { Spacer } from '../../../stacks/spacer.js';
3
+ import { Headline } from '../../../typography/index.js';
4
+ import { MobileButton } from '../../actions/button/mobile_button.js';
5
+ import { CrossIcon } from '@tcn/icons/cross_icon.js';
6
+ import { clsx } from 'clsx';
7
+ import styles from './mobile_overlay_header.module.css';
8
+
9
+ export interface MobileOverlayHeaderProps {
10
+ title: string;
11
+ onClose: () => void;
12
+ }
13
+
14
+ export function MobileOverlayHeader({ title, onClose }: MobileOverlayHeaderProps) {
15
+ return (
16
+ <HStack
17
+ width="100%"
18
+ height="auto"
19
+ className={clsx(styles['mobile-overlay-header'], 'tcn-mobile-overlay-header')}
20
+ padding="8px"
21
+ >
22
+ <Headline size="sm">{title}</Headline>
23
+ <Spacer />
24
+ <MobileButton hierarchy="tertiary" width="auto" onClick={onClose}>
25
+ <CrossIcon size="md" />
26
+ </MobileButton>
27
+ </HStack>
28
+ );
29
+ }
@@ -0,0 +1,4 @@
1
+ export * from './date_picker/mobile_date_picker.js';
2
+ export * from './date_picker/mobile_date_picker_input.js';
3
+ export * from './date_picker/mobile_date_picker_header.js';
4
+ export * from './date_picker/mobile_date_picker_time_selector.js';
@@ -0,0 +1,14 @@
1
+ import { Portal } from '../../overlay/portal/portal.js';
2
+ import { MobileViewport } from '../viewport/mobile_viewport.js';
3
+
4
+ export interface MobilePortalProps {
5
+ children: React.ReactNode;
6
+ }
7
+
8
+ export function MobilePortal({ children }: MobilePortalProps) {
9
+ return (
10
+ <Portal>
11
+ <MobileViewport>{children}</MobileViewport>
12
+ </Portal>
13
+ );
14
+ }
@@ -0,0 +1,23 @@
1
+ .mobileViewport {
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ width: var(--vv-width);
6
+ height: var(--vv-height);
7
+ transform: translate(var(--vv-offset-left), var(--vv-offset-top));
8
+ transform-origin: top left;
9
+ overflow: scroll;
10
+ overscroll-behavior: none;
11
+ padding-top: env(safe-area-inset-top);
12
+ padding-right: env(safe-area-inset-right);
13
+ padding-bottom: env(safe-area-inset-bottom);
14
+ padding-left: env(safe-area-inset-left);
15
+ touch-action: none;
16
+ }
17
+
18
+ .mobileViewport > div {
19
+ /* This captures the horrible document element scrollbar*/
20
+ width: calc(100% + 1px);
21
+ height: calc(100% + 1px);
22
+ overflow: hidden;
23
+ }
@@ -0,0 +1,80 @@
1
+ import React, { useLayoutEffect, useRef } from 'react';
2
+ import styles from './mobile_viewport.module.css';
3
+ import { clsx } from 'clsx';
4
+
5
+ interface MobileViewportProps {
6
+ children?: React.ReactNode;
7
+ className?: string;
8
+ style?: React.CSSProperties;
9
+ }
10
+
11
+ /**
12
+ * MobileRoot: an app-like viewport container that tracks the Visual Viewport.
13
+ *
14
+ * Exposes CSS variables on the root element:
15
+ * --vv-width: px (visual viewport width)
16
+ * --vv-height: px (visual viewport height)
17
+ * --vv-offset-top: px
18
+ * --vv-offset-left: px
19
+ * --keyboard-inset: px (how much the keyboard overlaps the bottom of the layout viewport)
20
+ *
21
+ * Also relies on safe-area env vars for padding (iOS notch/home indicator).
22
+ */
23
+ export function MobileViewport({ children, className, style }: MobileViewportProps) {
24
+ const ref = useRef<HTMLDivElement | null>(null);
25
+
26
+ // Keep the root sized to the *visual viewport* and publish CSS vars.
27
+ useLayoutEffect(() => {
28
+ const el = ref.current;
29
+ if (!el) return;
30
+
31
+ const vv = window.visualViewport;
32
+
33
+ const update = () => {
34
+ // Fallback if VisualViewport is missing (rare now, but safe).
35
+ const vvWidth = vv?.width ?? window.innerWidth;
36
+ const vvHeight = vv?.height ?? window.innerHeight;
37
+ const vvOffsetTop = vv?.offsetTop ?? 0;
38
+ const vvOffsetLeft = vv?.offsetLeft ?? 0;
39
+
40
+ // Keyboard overlap estimate.
41
+ // Works well cross-platform: when keyboard opens, vvHeight shrinks.
42
+ // offsetTop matters most on iOS (viewport can shift).
43
+ const keyboardInset = Math.max(0, window.innerHeight - vvHeight - vvOffsetTop);
44
+
45
+ el.style.setProperty('--vv-width', `${vvWidth}px`);
46
+ el.style.setProperty('--vv-height', `${vvHeight}px`);
47
+ el.style.setProperty('--vv-offset-top', `${vvOffsetTop}px`);
48
+ el.style.setProperty('--vv-offset-left', `${vvOffsetLeft}px`);
49
+ el.style.setProperty('--keyboard-inset', `${keyboardInset}px`);
50
+ };
51
+
52
+ update();
53
+
54
+ // VisualViewport events are the most accurate for keyboard + browser UI changes.
55
+ vv?.addEventListener('resize', update);
56
+ vv?.addEventListener('scroll', update);
57
+
58
+ // Window resize helps in a few Android/WebView edge cases.
59
+ window.addEventListener('resize', update);
60
+ window.addEventListener('orientationchange', update);
61
+
62
+ return () => {
63
+ vv?.removeEventListener('resize', update);
64
+ vv?.removeEventListener('scroll', update);
65
+ window.removeEventListener('resize', update);
66
+ window.removeEventListener('orientationchange', update);
67
+ };
68
+ }, []);
69
+
70
+ return (
71
+ <div
72
+ ref={ref}
73
+ id="mobile-vieport"
74
+ className={clsx(styles['mobileViewport'], className, 'tcn-mobile-viewport')}
75
+ style={style}
76
+ >
77
+ <div>{children}</div>
78
+ </div>
79
+ );
80
+ }
@@ -1,4 +1,4 @@
1
- import { useLayoutEffect } from 'react';
1
+ import React, { useLayoutEffect } from 'react';
2
2
  import { useTabs } from '../context.js';
3
3
  import { useTrackActiveItemRectangle } from '../../../../utils/css_utils.js';
4
4