@remix-run/ui 0.3.0 → 0.5.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 (434) hide show
  1. package/README.md +116 -157
  2. package/dist/accordion/index.d.ts +46 -0
  3. package/dist/accordion/index.js +142 -0
  4. package/dist/accordion/index.js.map +1 -0
  5. package/dist/accordion/primitives.d.ts +104 -0
  6. package/dist/accordion/primitives.js +312 -0
  7. package/dist/accordion/primitives.js.map +1 -0
  8. package/dist/{components/anchor/anchor.js → anchor/index.js} +1 -1
  9. package/dist/anchor/index.js.map +1 -0
  10. package/dist/animation/animate-layout-mixin.js +1 -1
  11. package/dist/animation/animate-layout-mixin.js.map +1 -1
  12. package/dist/animation/animate-mixins.js +2 -2
  13. package/dist/animation/animate-mixins.js.map +1 -1
  14. package/dist/animation/demos/color-interpolation.js +1 -1
  15. package/dist/animation/demos/color-interpolation.js.map +1 -1
  16. package/dist/animation/demos/drag-release.d.ts +1 -1
  17. package/dist/animation/demos/hold-to-confirm.d.ts +3 -3
  18. package/dist/animation/demos/material-ripple.js +1 -3
  19. package/dist/animation/demos/material-ripple.js.map +1 -1
  20. package/dist/animation/demos/reordering.js +9 -6
  21. package/dist/animation/demos/reordering.js.map +1 -1
  22. package/dist/animation/index.js +4 -4
  23. package/dist/animation/spring.js.map +1 -1
  24. package/dist/{components/breadcrumbs/breadcrumbs.js → breadcrumbs/index.js} +19 -19
  25. package/dist/breadcrumbs/index.js.map +1 -0
  26. package/dist/button/index.d.ts +15 -0
  27. package/dist/button/index.js +128 -0
  28. package/dist/button/index.js.map +1 -0
  29. package/dist/checkbox/index.d.ts +14 -0
  30. package/dist/checkbox/index.js +127 -0
  31. package/dist/checkbox/index.js.map +1 -0
  32. package/dist/combobox/index.d.ts +21 -0
  33. package/dist/combobox/index.js +58 -0
  34. package/dist/combobox/index.js.map +1 -0
  35. package/dist/{components/combobox/combobox.d.ts → combobox/primitives.d.ts} +4 -8
  36. package/dist/{components/combobox/combobox.js → combobox/primitives.js} +8 -61
  37. package/dist/combobox/primitives.js.map +1 -0
  38. package/dist/dev/refresh.d.ts +1 -0
  39. package/dist/dev/refresh.js +2 -0
  40. package/dist/dev/refresh.js.map +1 -0
  41. package/dist/index.d.ts +1 -1
  42. package/dist/index.js +14 -14
  43. package/dist/input/index.d.ts +13 -0
  44. package/dist/input/index.js +121 -0
  45. package/dist/input/index.js.map +1 -0
  46. package/dist/jsx-runtime.js +2 -2
  47. package/dist/listbox/flash-attribute.js.map +1 -0
  48. package/dist/{components/listbox/listbox.d.ts → listbox/index.d.ts} +2 -6
  49. package/dist/{components/listbox/listbox.js → listbox/index.js} +4 -82
  50. package/dist/listbox/index.js.map +1 -0
  51. package/dist/menu/hover-aim.js.map +1 -0
  52. package/dist/menu/index.d.ts +42 -0
  53. package/dist/menu/index.js +250 -0
  54. package/dist/menu/index.js.map +1 -0
  55. package/dist/{components/menu/menu.d.ts → menu/primitives.d.ts} +4 -33
  56. package/dist/{components/menu/menu.js → menu/primitives.js} +98 -315
  57. package/dist/menu/primitives.js.map +1 -0
  58. package/dist/{components/popover/popover.d.ts → popover/index.d.ts} +2 -4
  59. package/dist/{components/popover/popover.js → popover/index.js} +5 -48
  60. package/dist/popover/index.js.map +1 -0
  61. package/dist/{interactions/outside-click/outside-click-mixin.js → popover/outside-click.js} +1 -1
  62. package/dist/popover/outside-click.js.map +1 -0
  63. package/dist/popover/scroll-lock.d.ts +1 -0
  64. package/dist/{utils → popover}/scroll-lock.js +0 -18
  65. package/dist/popover/scroll-lock.js.map +1 -0
  66. package/dist/radio/index.d.ts +12 -0
  67. package/dist/radio/index.js +77 -0
  68. package/dist/radio/index.js.map +1 -0
  69. package/dist/runtime/client-entry-boundary.d.ts +14 -0
  70. package/dist/runtime/client-entry-boundary.js +29 -0
  71. package/dist/runtime/client-entry-boundary.js.map +1 -0
  72. package/dist/runtime/component.d.ts +19 -4
  73. package/dist/runtime/component.js +39 -9
  74. package/dist/runtime/component.js.map +1 -1
  75. package/dist/runtime/core/attributes.js +36 -3
  76. package/dist/runtime/core/attributes.js.map +1 -1
  77. package/dist/runtime/core/children.d.ts +2 -0
  78. package/dist/runtime/core/children.js +26 -2
  79. package/dist/runtime/core/children.js.map +1 -1
  80. package/dist/runtime/core/props.js +2 -2
  81. package/dist/runtime/core/vnode.d.ts +3 -3
  82. package/dist/runtime/core/vnode.js +22 -1
  83. package/dist/runtime/core/vnode.js.map +1 -1
  84. package/dist/runtime/create-element.d.ts +2 -2
  85. package/dist/runtime/create-element.js +3 -2
  86. package/dist/runtime/create-element.js.map +1 -1
  87. package/dist/runtime/diff-dom.js +294 -219
  88. package/dist/runtime/diff-dom.js.map +1 -1
  89. package/dist/runtime/diff-props.js +3 -3
  90. package/dist/runtime/dom.d.ts +12 -0
  91. package/dist/runtime/element-function.d.ts +3 -0
  92. package/dist/runtime/element-function.js +2 -0
  93. package/dist/runtime/element-function.js.map +1 -0
  94. package/dist/runtime/form-navigation.d.ts +25 -0
  95. package/dist/runtime/form-navigation.js +132 -0
  96. package/dist/runtime/form-navigation.js.map +1 -0
  97. package/dist/runtime/frame-resolution.d.ts +5 -0
  98. package/dist/runtime/frame-resolution.js +10 -0
  99. package/dist/runtime/frame-resolution.js.map +1 -0
  100. package/dist/runtime/frame.d.ts +58 -15
  101. package/dist/runtime/frame.js +367 -114
  102. package/dist/runtime/frame.js.map +1 -1
  103. package/dist/runtime/jsx.d.ts +1 -1
  104. package/dist/runtime/jsx.js +1 -1
  105. package/dist/runtime/jsx.js.map +1 -1
  106. package/dist/runtime/key.d.ts +1 -0
  107. package/dist/runtime/key.js +2 -0
  108. package/dist/runtime/key.js.map +1 -0
  109. package/dist/runtime/mixins/attrs-mixin.js +2 -2
  110. package/dist/runtime/mixins/link-mixin.js +4 -3
  111. package/dist/runtime/mixins/link-mixin.js.map +1 -1
  112. package/dist/runtime/mixins/mixin.d.ts +15 -10
  113. package/dist/runtime/mixins/mixin.js +4 -4
  114. package/dist/runtime/mixins/mixin.js.map +1 -1
  115. package/dist/runtime/mixins/on-mixin.js +1 -1
  116. package/dist/runtime/mixins/ref-mixin.js +1 -1
  117. package/dist/runtime/navigation.d.ts +4 -1
  118. package/dist/runtime/navigation.js +157 -32
  119. package/dist/runtime/navigation.js.map +1 -1
  120. package/dist/runtime/reconcile.d.ts +11 -10
  121. package/dist/runtime/reconcile.js +557 -423
  122. package/dist/runtime/reconcile.js.map +1 -1
  123. package/dist/runtime/refresh.d.ts +28 -0
  124. package/dist/runtime/refresh.js +31 -0
  125. package/dist/runtime/refresh.js.map +1 -0
  126. package/dist/runtime/render.js +1 -1
  127. package/dist/runtime/render.js.map +1 -1
  128. package/dist/runtime/run.d.ts +3 -1
  129. package/dist/runtime/run.js +15 -7
  130. package/dist/runtime/run.js.map +1 -1
  131. package/dist/runtime/scheduler.js +8 -16
  132. package/dist/runtime/scheduler.js.map +1 -1
  133. package/dist/runtime/to-vnode.d.ts +2 -2
  134. package/dist/runtime/to-vnode.js +68 -20
  135. package/dist/runtime/to-vnode.js.map +1 -1
  136. package/dist/runtime/vdom.d.ts +4 -2
  137. package/dist/runtime/vdom.js +89 -41
  138. package/dist/runtime/vdom.js.map +1 -1
  139. package/dist/runtime/vnode.d.ts +138 -67
  140. package/dist/runtime/vnode.js +17 -12
  141. package/dist/runtime/vnode.js.map +1 -1
  142. package/dist/select/index.d.ts +19 -0
  143. package/dist/select/index.js +95 -0
  144. package/dist/select/index.js.map +1 -0
  145. package/dist/select/keydown.js.map +1 -0
  146. package/dist/{components/select/select.d.ts → select/primitives.d.ts} +5 -7
  147. package/dist/{components/select/select.js → select/primitives.js} +11 -63
  148. package/dist/select/primitives.js.map +1 -0
  149. package/dist/server/stream.js +22 -29
  150. package/dist/server/stream.js.map +1 -1
  151. package/dist/shared/focus-styles.d.ts +1 -0
  152. package/dist/shared/focus-styles.js +2 -0
  153. package/dist/shared/focus-styles.js.map +1 -0
  154. package/dist/shared/icons.d.ts +9 -0
  155. package/dist/shared/icons.js +42 -0
  156. package/dist/shared/icons.js.map +1 -0
  157. package/dist/shared/listbox-popover-styles.d.ts +6 -0
  158. package/dist/shared/listbox-popover-styles.js +137 -0
  159. package/dist/shared/listbox-popover-styles.js.map +1 -0
  160. package/dist/shared/style-values.d.ts +78 -0
  161. package/dist/shared/style-values.js +88 -0
  162. package/dist/shared/style-values.js.map +1 -0
  163. package/dist/{interactions/typeahead/typeahead-mixin.js → shared/typeahead.js} +1 -1
  164. package/dist/shared/typeahead.js.map +1 -0
  165. package/dist/shared/wait-for-css-transition.js.map +1 -0
  166. package/dist/shared/wait.js.map +1 -0
  167. package/dist/style/css-mixin.js +3 -3
  168. package/dist/style/index.js +2 -2
  169. package/dist/style/style.js +25 -6
  170. package/dist/style/style.js.map +1 -1
  171. package/dist/style/stylesheet.d.ts +0 -1
  172. package/dist/style/stylesheet.js +13 -54
  173. package/dist/style/stylesheet.js.map +1 -1
  174. package/dist/tabs/index.d.ts +32 -0
  175. package/dist/tabs/index.js +157 -0
  176. package/dist/tabs/index.js.map +1 -0
  177. package/dist/tabs/primitives.d.ts +57 -0
  178. package/dist/tabs/primitives.js +238 -0
  179. package/dist/tabs/primitives.js.map +1 -0
  180. package/dist/test.js +1 -1
  181. package/dist/toggle/index.d.ts +9 -0
  182. package/dist/toggle/index.js +108 -0
  183. package/dist/toggle/index.js.map +1 -0
  184. package/dist/toggle/primitives.d.ts +29 -0
  185. package/dist/toggle/primitives.js +127 -0
  186. package/dist/toggle/primitives.js.map +1 -0
  187. package/package.json +81 -49
  188. package/src/{components/accordion → accordion}/README.md +50 -14
  189. package/src/accordion/index.tsx +285 -0
  190. package/src/accordion/primitives.tsx +512 -0
  191. package/src/{components/anchor → anchor}/README.md +37 -2
  192. package/src/animation/animate-mixins.ts +3 -3
  193. package/src/animation/demos/color-interpolation.tsx +1 -1
  194. package/src/animation/demos/reordering.tsx +9 -6
  195. package/src/{components/breadcrumbs → breadcrumbs}/README.md +4 -4
  196. package/src/{components/breadcrumbs/breadcrumbs.tsx → breadcrumbs/index.tsx} +18 -18
  197. package/src/button/README.md +44 -0
  198. package/src/button/index.ts +168 -0
  199. package/src/checkbox/README.md +59 -0
  200. package/src/checkbox/index.ts +164 -0
  201. package/src/{components/combobox → combobox}/README.md +58 -9
  202. package/src/combobox/index.tsx +112 -0
  203. package/src/{components/combobox/combobox.tsx → combobox/primitives.tsx} +5 -91
  204. package/src/dev/refresh.ts +1 -0
  205. package/src/index.ts +1 -1
  206. package/src/input/README.md +52 -0
  207. package/src/input/index.ts +147 -0
  208. package/src/{components/listbox → listbox}/README.md +9 -41
  209. package/src/{components/listbox/listbox.ts → listbox/index.ts} +2 -87
  210. package/src/{components/menu → menu}/README.md +55 -14
  211. package/src/menu/index.tsx +354 -0
  212. package/src/{components/menu/menu.tsx → menu/primitives.tsx} +99 -413
  213. package/src/{components/popover → popover}/README.md +20 -39
  214. package/src/{components/popover/popover.ts → popover/index.ts} +3 -57
  215. package/src/{utils → popover}/scroll-lock.ts +0 -28
  216. package/src/radio/README.md +53 -0
  217. package/src/radio/index.ts +101 -0
  218. package/src/runtime/client-entry-boundary.ts +54 -0
  219. package/src/runtime/component.ts +65 -16
  220. package/src/runtime/core/attributes.ts +35 -1
  221. package/src/runtime/core/children.ts +24 -2
  222. package/src/runtime/core/vnode.ts +25 -4
  223. package/src/runtime/create-element.ts +6 -5
  224. package/src/runtime/demos/readme.demo.tsx +20 -18
  225. package/src/runtime/diff-dom.ts +358 -243
  226. package/src/runtime/dom.ts +331 -214
  227. package/src/runtime/element-function.ts +1 -0
  228. package/src/runtime/event-listeners.ts +1 -1
  229. package/src/runtime/form-navigation.ts +184 -0
  230. package/src/runtime/frame-resolution.ts +13 -0
  231. package/src/runtime/frame.ts +482 -124
  232. package/src/runtime/jsx.ts +3 -5
  233. package/src/runtime/key.ts +1 -0
  234. package/src/runtime/mixins/link-mixin.ts +1 -0
  235. package/src/runtime/mixins/mixin.ts +21 -18
  236. package/src/runtime/navigation.ts +204 -30
  237. package/src/runtime/reconcile.ts +769 -760
  238. package/src/runtime/refresh.ts +46 -0
  239. package/src/runtime/run.ts +12 -2
  240. package/src/runtime/scheduler.ts +9 -29
  241. package/src/runtime/to-vnode.ts +85 -23
  242. package/src/runtime/vdom.ts +91 -69
  243. package/src/runtime/vnode.ts +192 -88
  244. package/src/{components/select → select}/README.md +29 -19
  245. package/src/select/index.tsx +159 -0
  246. package/src/{components/select/select.tsx → select/primitives.tsx} +10 -98
  247. package/src/server/stream.ts +25 -31
  248. package/src/shared/focus-styles.ts +2 -0
  249. package/src/shared/icons.tsx +62 -0
  250. package/src/shared/listbox-popover-styles.ts +146 -0
  251. package/src/shared/style-values.ts +165 -0
  252. package/src/style/style.ts +25 -6
  253. package/src/style/stylesheet.ts +32 -57
  254. package/src/tabs/README.md +141 -0
  255. package/src/tabs/index.tsx +245 -0
  256. package/src/tabs/primitives.ts +365 -0
  257. package/src/test/README.md +151 -60
  258. package/src/toggle/README.md +56 -0
  259. package/src/toggle/index.tsx +136 -0
  260. package/src/toggle/primitives.ts +192 -0
  261. package/dist/animation/demos/animation.demo.d.ts +0 -5
  262. package/dist/animation/demos/animation.demo.js +0 -92
  263. package/dist/animation/demos/animation.demo.js.map +0 -1
  264. package/dist/animation/demos/spring.demo.d.ts +0 -6
  265. package/dist/animation/demos/spring.demo.js +0 -304
  266. package/dist/animation/demos/spring.demo.js.map +0 -1
  267. package/dist/components/accordion/accordion.d.ts +0 -92
  268. package/dist/components/accordion/accordion.js +0 -335
  269. package/dist/components/accordion/accordion.js.map +0 -1
  270. package/dist/components/accordion/demos/card.demo.d.ts +0 -7
  271. package/dist/components/accordion/demos/card.demo.js +0 -59
  272. package/dist/components/accordion/demos/card.demo.js.map +0 -1
  273. package/dist/components/accordion/demos/multiple.demo.d.ts +0 -7
  274. package/dist/components/accordion/demos/multiple.demo.js +0 -20
  275. package/dist/components/accordion/demos/multiple.demo.js.map +0 -1
  276. package/dist/components/accordion/demos/overview.demo.d.ts +0 -7
  277. package/dist/components/accordion/demos/overview.demo.js +0 -20
  278. package/dist/components/accordion/demos/overview.demo.js.map +0 -1
  279. package/dist/components/anchor/anchor.js.map +0 -1
  280. package/dist/components/breadcrumbs/basic.demo.d.ts +0 -6
  281. package/dist/components/breadcrumbs/basic.demo.js +0 -15
  282. package/dist/components/breadcrumbs/basic.demo.js.map +0 -1
  283. package/dist/components/breadcrumbs/breadcrumbs.js.map +0 -1
  284. package/dist/components/breadcrumbs/separator.demo.d.ts +0 -6
  285. package/dist/components/breadcrumbs/separator.demo.js +0 -15
  286. package/dist/components/breadcrumbs/separator.demo.js.map +0 -1
  287. package/dist/components/button/button.d.ts +0 -105
  288. package/dist/components/button/button.js +0 -207
  289. package/dist/components/button/button.js.map +0 -1
  290. package/dist/components/button/demos/aliases.demo.d.ts +0 -7
  291. package/dist/components/button/demos/aliases.demo.js +0 -19
  292. package/dist/components/button/demos/aliases.demo.js.map +0 -1
  293. package/dist/components/button/demos/basic.demo.d.ts +0 -7
  294. package/dist/components/button/demos/basic.demo.js +0 -20
  295. package/dist/components/button/demos/basic.demo.js.map +0 -1
  296. package/dist/components/button/demos/states.demo.d.ts +0 -7
  297. package/dist/components/button/demos/states.demo.js +0 -30
  298. package/dist/components/button/demos/states.demo.js.map +0 -1
  299. package/dist/components/combobox/combobox.js.map +0 -1
  300. package/dist/components/combobox/overview.demo.d.ts +0 -7
  301. package/dist/components/combobox/overview.demo.js +0 -154
  302. package/dist/components/combobox/overview.demo.js.map +0 -1
  303. package/dist/components/glyph/glyph.d.ts +0 -14
  304. package/dist/components/glyph/glyph.js +0 -65
  305. package/dist/components/glyph/glyph.js.map +0 -1
  306. package/dist/components/listbox/listbox.js.map +0 -1
  307. package/dist/components/listbox/overview.demo.d.ts +0 -7
  308. package/dist/components/listbox/overview.demo.js +0 -65
  309. package/dist/components/listbox/overview.demo.js.map +0 -1
  310. package/dist/components/menu/demos/bubbling.demo.d.ts +0 -6
  311. package/dist/components/menu/demos/bubbling.demo.js +0 -16
  312. package/dist/components/menu/demos/bubbling.demo.js.map +0 -1
  313. package/dist/components/menu/demos/context-trigger.demo.d.ts +0 -7
  314. package/dist/components/menu/demos/context-trigger.demo.js +0 -87
  315. package/dist/components/menu/demos/context-trigger.demo.js.map +0 -1
  316. package/dist/components/menu/demos/overview.demo.d.ts +0 -7
  317. package/dist/components/menu/demos/overview.demo.js +0 -33
  318. package/dist/components/menu/demos/overview.demo.js.map +0 -1
  319. package/dist/components/menu/hover-aim.js.map +0 -1
  320. package/dist/components/menu/menu.js.map +0 -1
  321. package/dist/components/popover/overview.demo.d.ts +0 -7
  322. package/dist/components/popover/overview.demo.js +0 -65
  323. package/dist/components/popover/overview.demo.js.map +0 -1
  324. package/dist/components/popover/popover.js.map +0 -1
  325. package/dist/components/select/deconstructed.demo.d.ts +0 -7
  326. package/dist/components/select/deconstructed.demo.js +0 -54
  327. package/dist/components/select/deconstructed.demo.js.map +0 -1
  328. package/dist/components/select/overview.demo.d.ts +0 -6
  329. package/dist/components/select/overview.demo.js +0 -28
  330. package/dist/components/select/overview.demo.js.map +0 -1
  331. package/dist/components/select/select.js.map +0 -1
  332. package/dist/components/separator/separator.d.ts +0 -2
  333. package/dist/components/separator/separator.js +0 -15
  334. package/dist/components/separator/separator.js.map +0 -1
  335. package/dist/components/tabs/tabs.d.ts +0 -78
  336. package/dist/components/tabs/tabs.js +0 -339
  337. package/dist/components/tabs/tabs.js.map +0 -1
  338. package/dist/interactions/keydown/keydown.js.map +0 -1
  339. package/dist/interactions/outside-click/outside-click-mixin.js.map +0 -1
  340. package/dist/interactions/typeahead/typeahead-mixin.js.map +0 -1
  341. package/dist/runtime/demos/basic.demo.d.ts +0 -6
  342. package/dist/runtime/demos/basic.demo.js +0 -16
  343. package/dist/runtime/demos/basic.demo.js.map +0 -1
  344. package/dist/runtime/demos/controlled-uncontrolled-values.demo.d.ts +0 -6
  345. package/dist/runtime/demos/controlled-uncontrolled-values.demo.js +0 -77
  346. package/dist/runtime/demos/controlled-uncontrolled-values.demo.js.map +0 -1
  347. package/dist/runtime/demos/keyed-list.demo.d.ts +0 -6
  348. package/dist/runtime/demos/keyed-list.demo.js +0 -62
  349. package/dist/runtime/demos/keyed-list.demo.js.map +0 -1
  350. package/dist/runtime/demos/readme.demo.d.ts +0 -5
  351. package/dist/runtime/demos/readme.demo.js +0 -396
  352. package/dist/runtime/demos/readme.demo.js.map +0 -1
  353. package/dist/theme/contract.d.ts +0 -61
  354. package/dist/theme/contract.js +0 -131
  355. package/dist/theme/contract.js.map +0 -1
  356. package/dist/theme/glyph-contract.d.ts +0 -11
  357. package/dist/theme/glyph-contract.js +0 -34
  358. package/dist/theme/glyph-contract.js.map +0 -1
  359. package/dist/theme/presets/rmx-01/glyphs.d.ts +0 -2
  360. package/dist/theme/presets/rmx-01/glyphs.js +0 -252
  361. package/dist/theme/presets/rmx-01/glyphs.js.map +0 -1
  362. package/dist/theme/presets/rmx-01/index.d.ts +0 -4
  363. package/dist/theme/presets/rmx-01/index.js +0 -119
  364. package/dist/theme/presets/rmx-01/index.js.map +0 -1
  365. package/dist/theme/runtime.d.ts +0 -2
  366. package/dist/theme/runtime.js +0 -84
  367. package/dist/theme/runtime.js.map +0 -1
  368. package/dist/theme/theme.d.ts +0 -6
  369. package/dist/theme/theme.js +0 -5
  370. package/dist/theme/theme.js.map +0 -1
  371. package/dist/utils/flash-attribute.js.map +0 -1
  372. package/dist/utils/scroll-lock.d.ts +0 -3
  373. package/dist/utils/scroll-lock.js.map +0 -1
  374. package/dist/utils/wait-for-css-transition.js.map +0 -1
  375. package/dist/utils/wait.js.map +0 -1
  376. package/src/animation/demos/animation.demo.tsx +0 -194
  377. package/src/animation/demos/spring.demo.tsx +0 -385
  378. package/src/components/accordion/accordion.tsx +0 -565
  379. package/src/components/accordion/demos/card.demo.tsx +0 -114
  380. package/src/components/accordion/demos/multiple.demo.tsx +0 -57
  381. package/src/components/accordion/demos/overview.demo.tsx +0 -57
  382. package/src/components/breadcrumbs/basic.demo.tsx +0 -18
  383. package/src/components/breadcrumbs/separator.demo.tsx +0 -19
  384. package/src/components/button/README.md +0 -44
  385. package/src/components/button/button.tsx +0 -286
  386. package/src/components/button/demos/aliases.demo.tsx +0 -28
  387. package/src/components/button/demos/basic.demo.tsx +0 -31
  388. package/src/components/button/demos/states.demo.tsx +0 -53
  389. package/src/components/combobox/overview.demo.tsx +0 -200
  390. package/src/components/glyph/README.md +0 -72
  391. package/src/components/glyph/glyph.tsx +0 -110
  392. package/src/components/listbox/overview.demo.tsx +0 -102
  393. package/src/components/menu/demos/bubbling.demo.tsx +0 -35
  394. package/src/components/menu/demos/context-trigger.demo.tsx +0 -133
  395. package/src/components/menu/demos/overview.demo.tsx +0 -77
  396. package/src/components/popover/overview.demo.tsx +0 -144
  397. package/src/components/select/deconstructed.demo.tsx +0 -96
  398. package/src/components/select/overview.demo.tsx +0 -52
  399. package/src/components/separator/separator.ts +0 -19
  400. package/src/components/tabs/README.md +0 -105
  401. package/src/components/tabs/tabs.tsx +0 -504
  402. package/src/runtime/demos/basic.demo.tsx +0 -21
  403. package/src/runtime/demos/controlled-uncontrolled-values.demo.tsx +0 -177
  404. package/src/runtime/demos/keyed-list.demo.tsx +0 -94
  405. package/src/theme/README.md +0 -103
  406. package/src/theme/contract.ts +0 -215
  407. package/src/theme/glyph-contract.ts +0 -59
  408. package/src/theme/presets/rmx-01/glyphs.tsx +0 -308
  409. package/src/theme/presets/rmx-01/index.ts +0 -123
  410. package/src/theme/runtime.ts +0 -119
  411. package/src/theme/theme.ts +0 -15
  412. package/src/utils/scroll-lock/README.md +0 -33
  413. /package/dist/{components/anchor/anchor.d.ts → anchor/index.d.ts} +0 -0
  414. /package/dist/{components/breadcrumbs/breadcrumbs.d.ts → breadcrumbs/index.d.ts} +0 -0
  415. /package/dist/{utils → listbox}/flash-attribute.d.ts +0 -0
  416. /package/dist/{utils → listbox}/flash-attribute.js +0 -0
  417. /package/dist/{components/menu → menu}/hover-aim.d.ts +0 -0
  418. /package/dist/{components/menu → menu}/hover-aim.js +0 -0
  419. /package/dist/{interactions/outside-click/outside-click-mixin.d.ts → popover/outside-click.d.ts} +0 -0
  420. /package/dist/{interactions/keydown → select}/keydown.d.ts +0 -0
  421. /package/dist/{interactions/keydown → select}/keydown.js +0 -0
  422. /package/dist/{interactions/typeahead/typeahead-mixin.d.ts → shared/typeahead.d.ts} +0 -0
  423. /package/dist/{utils → shared}/wait-for-css-transition.d.ts +0 -0
  424. /package/dist/{utils → shared}/wait-for-css-transition.js +0 -0
  425. /package/dist/{utils → shared}/wait.d.ts +0 -0
  426. /package/dist/{utils → shared}/wait.js +0 -0
  427. /package/src/{components/anchor/anchor.ts → anchor/index.ts} +0 -0
  428. /package/src/{utils → listbox}/flash-attribute.ts +0 -0
  429. /package/src/{components/menu → menu}/hover-aim.ts +0 -0
  430. /package/src/{interactions/outside-click/outside-click-mixin.ts → popover/outside-click.ts} +0 -0
  431. /package/src/{interactions/keydown → select}/keydown.ts +0 -0
  432. /package/src/{interactions/typeahead/typeahead-mixin.ts → shared/typeahead.ts} +0 -0
  433. /package/src/{utils → shared}/wait-for-css-transition.ts +0 -0
  434. /package/src/{utils → shared}/wait.ts +0 -0
@@ -19,8 +19,22 @@ export interface CSSProps extends DOMStyleProperties {
19
19
  type StyleObject = Record<string, unknown>
20
20
 
21
21
  // Convert camelCase CSS properties to kebab-case
22
+ // Property names repeat constantly across renders; cache conversions instead
23
+ // of running a regex each time.
24
+ const CAMEL_TO_KEBAB_CACHE_LIMIT = 256
25
+ const camelToKebabCache = new Map<string, string>()
26
+
22
27
  function camelToKebab(str: string): string {
23
- return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)
28
+ let cached = camelToKebabCache.get(str)
29
+ if (cached === undefined) {
30
+ cached = str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)
31
+ if (camelToKebabCache.size >= CAMEL_TO_KEBAB_CACHE_LIMIT) {
32
+ let oldest = camelToKebabCache.keys().next()
33
+ if (!oldest.done) camelToKebabCache.delete(oldest.value)
34
+ }
35
+ camelToKebabCache.set(str, cached)
36
+ }
37
+ return cached
24
38
  }
25
39
 
26
40
  // Properties that should remain unitless (numeric values without px)
@@ -81,18 +95,23 @@ function isKeyframesAtRule(key: string): boolean {
81
95
  )
82
96
  }
83
97
 
84
- // Generate a hash for style objects to create unique class names
98
+ // Generate a hash for style objects to create unique class names.
99
+ // Class names are content-addressed — a collision silently applies the wrong
100
+ // styles — so use two independent 32-bit FNV-1a passes (~64 bits of hash
101
+ // space) rather than a single 32-bit hash. Must be deterministic across
102
+ // server and client.
85
103
  function hashStyle(obj: any): string {
86
104
  // Sort keys to ensure consistent hashing, but include values in the string
87
105
  let sortedEntries = Object.entries(obj).sort(([a], [b]) => a.localeCompare(b))
88
106
  let str = JSON.stringify(sortedEntries)
89
- let hash = 0
107
+ let h1 = 0x811c9dc5
108
+ let h2 = 0xcbf29ce4
90
109
  for (let i = 0; i < str.length; i++) {
91
110
  let char = str.charCodeAt(i)
92
- hash = (hash << 5) - hash + char
93
- hash = hash & hash // Convert to 32-bit integer
111
+ h1 = Math.imul(h1 ^ char, 0x01000193) >>> 0
112
+ h2 = Math.imul(h2 ^ char, 0x01000193) >>> 0
94
113
  }
95
- return Math.abs(hash).toString(36)
114
+ return h1.toString(36) + h2.toString(36)
96
115
  }
97
116
 
98
117
  // Convert style object to CSS text
@@ -1,6 +1,26 @@
1
1
  import { REMIX_UI_STYLE_LAYER } from './layers.ts'
2
2
 
3
- type RuleEntry = { count: number; index: number }
3
+ // # Style ownership model
4
+ //
5
+ // Rules are content-addressed: a class name is a hash of the style object that
6
+ // produced it, so `.rmxc-x` always means the same declarations. A rule can
7
+ // never become *wrong* — only unused. That observation drives a two-tier
8
+ // lifetime model on a single document-level registry:
9
+ //
10
+ // - **Server-adopted rules are pinned.** Once a `<style data-rmx>` tag is
11
+ // adopted, its rule stays for the life of the manager. Frame reloads,
12
+ // island hydration, and streamed templates never need to agree on which
13
+ // scope "owns" a shared rule — adoption is additive and idempotent, and the
14
+ // registry is bounded by the set of unique style objects the server ever
15
+ // renders, not by render count.
16
+ //
17
+ // - **Client-inserted rules are refcounted.** Dynamic style objects (e.g.
18
+ // interpolated values) mint a new class per distinct value, so rules that
19
+ // only ever existed client-side are dropped when the last css mixin using
20
+ // them releases its ref. A refcounted rule upgrades to pinned if a server
21
+ // tag for the same selector is adopted later.
22
+
23
+ type RuleEntry = { count: number; index: number; pinned: boolean }
4
24
  export type ServerStyleSource = ParentNode | Iterable<Node>
5
25
 
6
26
  export interface StyleManager {
@@ -10,7 +30,6 @@ export interface StyleManager {
10
30
  getGeneration(): number
11
31
  reset(): void
12
32
  adoptServerStyles(source: ServerStyleSource): Set<string>
13
- replaceServerStyles(source: ServerStyleSource): void
14
33
  selectors(): IterableIterator<string>
15
34
  dispose(): void
16
35
  }
@@ -84,17 +103,8 @@ export function createStyleManager(layer: string = REMIX_UI_STYLE_LAYER): StyleM
84
103
  let stylesheet: CSSStyleSheet | null = null
85
104
  let generation = 0
86
105
 
87
- // Track usage count and rule index per className
88
- // Using an object to track both count and index together
89
106
  let ruleMap = new Map<string, RuleEntry>()
90
107
 
91
- // Selectors currently held by a server-style adoption ref. We track this
92
- // separately from `ruleMap` so `replaceServerStyles` can release only the
93
- // adoption refs of selectors absent from the next page, without disturbing
94
- // selectors that exist solely because a client-side css mixin inserted them
95
- // (e.g. transient UI state that the server never rendered).
96
- let adoptedSelectors = new Set<string>()
97
-
98
108
  function getStylesheet(): CSSStyleSheet {
99
109
  if (!stylesheet) {
100
110
  stylesheet = new CSSStyleSheet()
@@ -122,15 +132,11 @@ export function createStyleManager(layer: string = REMIX_UI_STYLE_LAYER): StyleM
122
132
  let selector = getStyleSelector(styleEl)
123
133
  if (!selector) return undefined
124
134
 
125
- if (ruleMap.has(selector)) {
126
- // Already tracked. Take an adoption ref if we don't already have one —
127
- // the rule may have been inserted by a client-side css mixin first and
128
- // the SSR'd style tag arrived afterwards (e.g. a streamed fragment).
129
- if (!adoptedSelectors.has(selector)) {
130
- let entry = ruleMap.get(selector)!
131
- entry.count++
132
- adoptedSelectors.add(selector)
133
- }
135
+ let entry = ruleMap.get(selector)
136
+ if (entry) {
137
+ // The rule already exists either a previous adoption or a client-side
138
+ // css mixin inserted it first. Pin it so it outlives any mixin refs.
139
+ entry.pinned = true
134
140
  styleEl.remove()
135
141
  return selector
136
142
  }
@@ -145,8 +151,7 @@ export function createStyleManager(layer: string = REMIX_UI_STYLE_LAYER): StyleM
145
151
  let sheet = getStylesheet()
146
152
  let index = sheet.cssRules.length
147
153
  sheet.insertRule(cssText, index)
148
- ruleMap.set(selector, { count: 1, index })
149
- adoptedSelectors.add(selector)
154
+ ruleMap.set(selector, { count: 0, index, pinned: true })
150
155
  styleEl.remove()
151
156
  return selector
152
157
  } catch {
@@ -157,7 +162,7 @@ export function createStyleManager(layer: string = REMIX_UI_STYLE_LAYER): StyleM
157
162
 
158
163
  function has(className: string) {
159
164
  let entry = ruleMap.get(className)
160
- return entry !== undefined && entry.count > 0
165
+ return entry !== undefined && (entry.pinned || entry.count > 0)
161
166
  }
162
167
 
163
168
  function getGeneration() {
@@ -168,8 +173,8 @@ export function createStyleManager(layer: string = REMIX_UI_STYLE_LAYER): StyleM
168
173
  let entry = ruleMap.get(className)
169
174
 
170
175
  if (entry) {
171
- // Already exists, just increment count
172
- entry.count++
176
+ // Pinned rules are permanent; there is nothing to count.
177
+ if (!entry.pinned) entry.count++
173
178
  return
174
179
  }
175
180
 
@@ -179,13 +184,13 @@ export function createStyleManager(layer: string = REMIX_UI_STYLE_LAYER): StyleM
179
184
  // This may throw for invalid CSS. If it does, we intentionally let it
180
185
  // bubble so the rule is not tracked unless insertion actually succeeds.
181
186
  sheet.insertRule(`@layer ${getStyleLayerName(className, layer)} { ${rule} }`, index)
182
- ruleMap.set(className, { count: 1, index })
187
+ ruleMap.set(className, { count: 1, index, pinned: false })
183
188
  }
184
189
 
185
190
  function remove(className: string) {
186
191
  let entry = ruleMap.get(className)
187
192
 
188
- if (!entry) return
193
+ if (!entry || entry.pinned) return
189
194
 
190
195
  // Decrement count
191
196
  entry.count--
@@ -200,9 +205,7 @@ export function createStyleManager(layer: string = REMIX_UI_STYLE_LAYER): StyleM
200
205
 
201
206
  // Remove from tracking
202
207
  ruleMap.delete(className)
203
- adoptedSelectors.delete(className)
204
208
 
205
- // TODO: just search and remove, stop re-indexing
206
209
  if (!stylesheet) return
207
210
  stylesheet.deleteRule(indexToDelete)
208
211
 
@@ -218,7 +221,6 @@ export function createStyleManager(layer: string = REMIX_UI_STYLE_LAYER): StyleM
218
221
  function reset() {
219
222
  clearStylesheet()
220
223
  ruleMap.clear()
221
- adoptedSelectors.clear()
222
224
  removeStylesheet()
223
225
  generation++
224
226
  }
@@ -235,31 +237,6 @@ export function createStyleManager(layer: string = REMIX_UI_STYLE_LAYER): StyleM
235
237
  return adopted
236
238
  }
237
239
 
238
- // Snapshot the currently-adopted server selectors, adopt the incoming
239
- // server styles additively, then release the adoption ref of any prior-only
240
- // selectors.
241
- //
242
- // Refcount-aware semantics keep preserved DOM styled: a prior-only selector
243
- // with no live css-mixin ref drops immediately, but one still referenced by
244
- // an active mixin (e.g. inside a hydration region that the DOM diff skipped)
245
- // stays in the stylesheet and is only fully removed when that mixin's
246
- // `remove` event eventually fires. This avoids the FOUC that a hard
247
- // `reset()` would cause between the style swap and the hydration re-render.
248
- //
249
- // Only adoption refs are considered — selectors that exist solely because a
250
- // client-side css mixin inserted them (e.g. transient UI state never
251
- // rendered by the server) are unaffected.
252
- function replaceServerStyles(source: ServerStyleSource): void {
253
- let prior = new Set(adoptedSelectors)
254
- let adopted = adoptServerStyles(source)
255
- for (let selector of prior) {
256
- if (!adopted.has(selector)) {
257
- adoptedSelectors.delete(selector)
258
- remove(selector)
259
- }
260
- }
261
- }
262
-
263
240
  function selectors(): IterableIterator<string> {
264
241
  return ruleMap.keys()
265
242
  }
@@ -268,7 +245,6 @@ export function createStyleManager(layer: string = REMIX_UI_STYLE_LAYER): StyleM
268
245
  removeStylesheet()
269
246
  // Clear internal state
270
247
  ruleMap.clear()
271
- adoptedSelectors.clear()
272
248
  generation++
273
249
  }
274
250
 
@@ -279,7 +255,6 @@ export function createStyleManager(layer: string = REMIX_UI_STYLE_LAYER): StyleM
279
255
  getGeneration,
280
256
  reset,
281
257
  adoptServerStyles,
282
- replaceServerStyles,
283
258
  selectors,
284
259
  dispose,
285
260
  }
@@ -0,0 +1,141 @@
1
+ # tabs
2
+
3
+ `Tabs` renders a tab control with one active tab and matching panels. Use it when related views share the same page space and the owning component may either control the active tab or let the tabs context manage it.
4
+
5
+ ## Component Usage
6
+
7
+ ```tsx
8
+ import { Tabs, TabList, Tab, TabPanel } from 'remix/ui/tabs'
9
+
10
+ export function ProjectTabs() {
11
+ return (
12
+ <Tabs defaultActiveTab="overview">
13
+ <TabList aria-label="Project sections">
14
+ <Tab name="overview">Overview</Tab>
15
+ <Tab name="activity">Activity</Tab>
16
+ <Tab name="settings">Settings</Tab>
17
+ </TabList>
18
+
19
+ <TabPanel name="overview">Project summary.</TabPanel>
20
+ <TabPanel name="activity">Recent changes.</TabPanel>
21
+ <TabPanel name="settings">Project settings.</TabPanel>
22
+ </Tabs>
23
+ )
24
+ }
25
+ ```
26
+
27
+ Control the active tab when state should live in the owning component:
28
+
29
+ ```tsx
30
+ import type { Handle } from 'remix/ui'
31
+ import { Tabs, TabList, Tab, TabPanel } from 'remix/ui/tabs'
32
+
33
+ export function ControlledTabs(handle: Handle) {
34
+ let activeTab = 'overview'
35
+
36
+ return () => (
37
+ <Tabs
38
+ activeTab={activeTab}
39
+ onActiveTabChange={(nextActiveTab) => {
40
+ activeTab = nextActiveTab
41
+ void handle.update()
42
+ }}
43
+ >
44
+ <TabList aria-label="Project sections">
45
+ <Tab name="overview">Overview</Tab>
46
+ <Tab name="activity">Activity</Tab>
47
+ </TabList>
48
+
49
+ <TabPanel name="overview">Project summary.</TabPanel>
50
+ <TabPanel name="activity">Recent changes.</TabPanel>
51
+ </Tabs>
52
+ )
53
+ }
54
+ ```
55
+
56
+ Listen for bubbling `TabsChangeEvent` events with `onTabsChange` from `remix/ui/tabs/primitives`.
57
+
58
+ ```tsx
59
+ import { onTabsChange } from 'remix/ui/tabs/primitives'
60
+ import { Tabs, TabList, Tab, TabPanel } from 'remix/ui/tabs'
61
+
62
+ export function TrackedTabs() {
63
+ return (
64
+ <div
65
+ mix={[
66
+ onTabsChange((event) => {
67
+ console.log(event.previousActiveTab, event.activeTab)
68
+ }),
69
+ ]}
70
+ >
71
+ <Tabs defaultActiveTab="overview">
72
+ <TabList aria-label="Project sections">
73
+ <Tab name="overview">Overview</Tab>
74
+ <Tab name="activity">Activity</Tab>
75
+ </TabList>
76
+ <TabPanel name="overview">Project summary.</TabPanel>
77
+ <TabPanel name="activity">Recent changes.</TabPanel>
78
+ </Tabs>
79
+ </div>
80
+ )
81
+ }
82
+ ```
83
+
84
+ ## Primitive Usage
85
+
86
+ Use the lower-level primitives when app code owns the markup and styles:
87
+
88
+ ```tsx
89
+ import * as tabs from 'remix/ui/tabs/primitives'
90
+ import { listStyle, panelStyle, rootStyle, tabStyle } from './tabs.styles'
91
+
92
+ export function PrimitiveTabs() {
93
+ return (
94
+ <tabs.Context defaultActiveTab="overview">
95
+ <div mix={[rootStyle, tabs.root()]}>
96
+ <div mix={[listStyle, tabs.list()]} aria-label="Project sections">
97
+ <button mix={[tabStyle, tabs.tab({ name: 'overview' })]} type="button">
98
+ Overview
99
+ </button>
100
+ <button mix={[tabStyle, tabs.tab({ name: 'activity' })]} type="button">
101
+ Activity
102
+ </button>
103
+ </div>
104
+
105
+ <div mix={[panelStyle, tabs.panel({ name: 'overview' })]}>Project summary.</div>
106
+ <div mix={[panelStyle, tabs.panel({ name: 'activity' })]}>Recent changes.</div>
107
+ </div>
108
+ </tabs.Context>
109
+ )
110
+ }
111
+ ```
112
+
113
+ ## `remix/ui/tabs`
114
+
115
+ - `Tabs`: root component. Supports controlled `activeTab`, uncontrolled `defaultActiveTab`, `onActiveTabChange`, `disabled`, and `size: 'md' | 'lg'`.
116
+ - `TabList`: tablist wrapper that lays out the tabs in a track and applies the tablist primitive.
117
+ - `Tab`: button for one tab `name`. The active tab uses the toggle slider treatment and button-sized text. Pass `disabled` to prevent activation.
118
+ - `TabPanel`: panel for one tab `name`.
119
+ - `rootStyle`, `listStyle`, `tabStyle`, and `panelStyle`: flat style mixins used by the component markup.
120
+ - `onTabsChange` and `TabsChangeEvent`: re-exported primitive event helpers.
121
+ - `TabsProps`, `TabListProps`, `TabProps`, `TabPanelProps`, and `TabsSize`: public TypeScript types for the composed APIs.
122
+
123
+ ## `remix/ui/tabs/primitives`
124
+
125
+ - `Context`: lower-level provider for custom tabs composition.
126
+ - `root()`: wires the root element and bubbling change events.
127
+ - `list()`: wires the tablist role and disabled state.
128
+ - `tab({ name, disabled })`: wires a tab button with selected state, ids, keyboard activation, and pointer activation.
129
+ - `panel({ name })`: wires the matching tab panel id, hidden state, inert state, and label relationship.
130
+ - `onTabsChange(...)`: event mixin for the bubbling `TabsChangeEvent`.
131
+ - `TabsChangeEvent`: bubbling event with `activeTab` and `previousActiveTab`.
132
+ - `TabsContextProps`, `TabsContextValue`, `TabsRegisteredTab`, `TabsActivationDirection`, `TabsRootOptions`, `TabListOptions`, `TabOptions`, and `TabPanelOptions`: primitive prop and option types for custom composition.
133
+
134
+ ## Behavior Notes
135
+
136
+ - If neither `activeTab` nor `defaultActiveTab` is provided, the first enabled tab becomes active.
137
+ - Arrow keys activate the next or previous enabled tab. `Home` and `End` activate the first and last enabled tabs.
138
+ - `Enter`, `Space`, and pointer clicks activate the focused tab.
139
+ - Root `disabled` disables every tab. Tab `disabled` only disables that tab.
140
+ - Tabs and panels are linked with generated ids through `aria-controls`, `aria-labelledby`, and `aria-selected`.
141
+ - Inactive panels receive `hidden`, `inert`, and `data-state="inactive"`.
@@ -0,0 +1,245 @@
1
+ import {
2
+ css,
3
+ type CSSMixinDescriptor,
4
+ type Handle,
5
+ type Props,
6
+ type RemixNode,
7
+ } from '@remix-run/ui'
8
+ import * as tabs from '@remix-run/ui/tabs/primitives'
9
+
10
+ export { TabsChangeEvent, onTabsChange } from '@remix-run/ui/tabs/primitives'
11
+
12
+ export type TabsSize = 'md' | 'lg'
13
+
14
+ export interface TabsProps extends Omit<Props<'div'>, 'children'> {
15
+ activeTab?: string
16
+ children?: RemixNode
17
+ defaultActiveTab?: string
18
+ disabled?: boolean
19
+ onActiveTabChange?: (activeTab: string) => void
20
+ size?: TabsSize
21
+ }
22
+
23
+ export interface TabListProps extends Omit<Props<'div'>, 'children'> {
24
+ children?: RemixNode
25
+ }
26
+
27
+ export interface TabProps extends Omit<Props<'button'>, 'children' | 'type'> {
28
+ children?: RemixNode
29
+ disabled?: boolean
30
+ name: string
31
+ type?: 'button' | 'submit' | 'reset'
32
+ }
33
+
34
+ export interface TabPanelProps extends Omit<Props<'div'>, 'children'> {
35
+ children?: RemixNode
36
+ name: string
37
+ }
38
+
39
+ const tabSliderBackground =
40
+ 'linear-gradient(180deg, rgba(0, 0, 0, 0) 33%, light-dark(rgba(0, 0, 0, 0.04), rgba(255, 255, 255, 0.08)) 100%), light-dark(#FFFFFF, #1a1a1a)'
41
+ const tabSliderShadow =
42
+ '0 0 0 0.5px light-dark(rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.12)), 0 1px 1px -0.5px rgba(0, 0, 0, 0.12), 0 2px 2px -1px rgba(0, 0, 0, 0.12), 0 4px 4px -2px rgba(0, 0, 0, 0.12), inset 0 0 2px 1px light-dark(#FFFFFF, rgba(255, 255, 255, 0.08))'
43
+
44
+ const tabsRootCss: CSSMixinDescriptor = css({
45
+ '--rmx-tabs-height': '32px',
46
+ '--rmx-tabs-track-padding': '2px',
47
+ '--rmx-tabs-tab-padding-inline': '12px',
48
+ '--rmx-tabs-tab-shadow': '0 0 0 0 rgba(0, 0, 0, 0)',
49
+ '--rmx-tabs-tab-font-size': '12px',
50
+ '--rmx-tabs-tab-line-height': '17px',
51
+ '--rmx-tabs-gap': '12px',
52
+ boxSizing: 'border-box',
53
+ display: 'grid',
54
+ gap: 'var(--rmx-tabs-gap)',
55
+ minWidth: 0,
56
+ })
57
+
58
+ const tabsListCss: CSSMixinDescriptor = css({
59
+ boxSizing: 'border-box',
60
+ display: 'inline-flex',
61
+ alignItems: 'center',
62
+ gap: '2px',
63
+ width: 'max-content',
64
+ maxWidth: '100%',
65
+ minHeight: 'var(--rmx-tabs-height)',
66
+ padding: 'var(--rmx-tabs-track-padding)',
67
+ border: 0,
68
+ borderRadius: '9999px',
69
+ background:
70
+ 'linear-gradient(180deg, light-dark(rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.08)) 0%, rgba(0, 0, 0, 0) 100%), light-dark(#EBEBEB, #2c2c2c)',
71
+ boxShadow:
72
+ 'inset 0 0 4px 1px rgba(0, 0, 0, 0.08), inset 0 1px 1px rgba(0, 0, 0, 0.02), inset 0 2px 2px rgba(0, 0, 0, 0.02)',
73
+ overflowX: 'auto',
74
+ scrollbarWidth: 'none',
75
+ '&::-webkit-scrollbar': {
76
+ display: 'none',
77
+ },
78
+ '&[aria-disabled="true"]': {
79
+ opacity: 0.55,
80
+ },
81
+ })
82
+
83
+ const tabsTabCss: CSSMixinDescriptor = css({
84
+ '--rmx-tabs-tab-focus-shadow':
85
+ '0 0 0 1px light-dark(#3573F6, #6eaaff), var(--rmx-tabs-tab-shadow), 0 0 0 4px light-dark(rgba(53, 115, 246, 0.1), rgba(110, 170, 255, 0.18)), 0 6px 32px 4px light-dark(rgba(53, 115, 246, 0.08), rgba(110, 170, 255, 0.14)), inset 0 0 8px 1px light-dark(rgba(53, 115, 246, 0.05), rgba(110, 170, 255, 0.1))',
86
+ appearance: 'none',
87
+ margin: 0,
88
+ boxSizing: 'border-box',
89
+ position: 'relative',
90
+ cursor: 'pointer',
91
+ display: 'inline-flex',
92
+ alignItems: 'center',
93
+ justifyContent: 'center',
94
+ flexDirection: 'row',
95
+ gap: '4px',
96
+ width: 'max-content',
97
+ maxWidth: '100%',
98
+ minWidth: 0,
99
+ height: 'calc(var(--rmx-tabs-height) - (var(--rmx-tabs-track-padding) * 2))',
100
+ minHeight: 'calc(var(--rmx-tabs-height) - (var(--rmx-tabs-track-padding) * 2))',
101
+ paddingBlock: 0,
102
+ paddingInline: 'var(--rmx-tabs-tab-padding-inline)',
103
+ border: 0,
104
+ borderRadius: '999px',
105
+ background: 'transparent',
106
+ boxShadow: 'var(--rmx-tabs-tab-shadow)',
107
+ color: 'light-dark(#707070, #b3b3b3)',
108
+ fontFamily: '"Inter Variable", Inter, ui-sans-serif, system-ui, sans-serif',
109
+ fontStyle: 'normal',
110
+ fontWeight: 500,
111
+ fontSize: 'var(--rmx-tabs-tab-font-size)',
112
+ lineHeight: 'var(--rmx-tabs-tab-line-height)',
113
+ fontFeatureSettings: '"ss01" on, "cv01" on',
114
+ letterSpacing: 0,
115
+ textAlign: 'center',
116
+ textDecoration: 'none',
117
+ textShadow: 'none',
118
+ userSelect: 'none',
119
+ WebkitUserSelect: 'none',
120
+ verticalAlign: 'top',
121
+ whiteSpace: 'nowrap',
122
+ '&[data-state="inactive"]:hover:not(:disabled):not([aria-disabled="true"])': {
123
+ background: 'light-dark(rgba(16, 16, 16, 0.05), rgba(236, 236, 236, 0.1))',
124
+ color: 'light-dark(#101010, #ececec)',
125
+ },
126
+ '&[data-state="inactive"]:active:not(:disabled):not([aria-disabled="true"])': {
127
+ background: 'light-dark(rgba(16, 16, 16, 0.08), rgba(236, 236, 236, 0.14))',
128
+ },
129
+ '&[data-state="active"]': {
130
+ background: tabSliderBackground,
131
+ '--rmx-tabs-tab-shadow': tabSliderShadow,
132
+ color: 'light-dark(#101010, #ececec)',
133
+ textShadow: '0 1px 0 light-dark(#FFFFFF, rgb(0 0 0 / 0.35))',
134
+ },
135
+ '&[data-state="active"]:hover:not(:disabled):not([aria-disabled="true"])': {
136
+ background: tabSliderBackground,
137
+ },
138
+ '&[data-state="active"]:active:not(:disabled):not([aria-disabled="true"])': {
139
+ background: tabSliderBackground,
140
+ },
141
+ '&:disabled, &[aria-disabled="true"]': {
142
+ cursor: 'not-allowed',
143
+ opacity: 0.55,
144
+ },
145
+ '&:focus-visible': {
146
+ outline: 0,
147
+ boxShadow: 'var(--rmx-tabs-tab-focus-shadow)',
148
+ },
149
+ })
150
+
151
+ const tabsPanelCss: CSSMixinDescriptor = css({
152
+ minWidth: 0,
153
+ color: 'light-dark(#101010, #ececec)',
154
+ fontFamily: '"Inter Variable", Inter, ui-sans-serif, system-ui, sans-serif',
155
+ fontSize: '13px',
156
+ lineHeight: '20px',
157
+ letterSpacing: 0,
158
+ '&[hidden]': {
159
+ display: 'none',
160
+ },
161
+ })
162
+
163
+ const sizeStyles = {
164
+ md: css({}),
165
+ lg: css({
166
+ '--rmx-tabs-height': '36px',
167
+ '--rmx-tabs-tab-padding-inline': '14px',
168
+ '--rmx-tabs-tab-font-size': '13px',
169
+ '--rmx-tabs-tab-line-height': '20px',
170
+ '--rmx-tabs-gap': '14px',
171
+ }),
172
+ } as const satisfies Record<TabsSize, CSSMixinDescriptor>
173
+
174
+ export const rootStyle = tabsRootCss
175
+ export const listStyle = tabsListCss
176
+ export const tabStyle = tabsTabCss
177
+ export const panelStyle = tabsPanelCss
178
+
179
+ export function Tabs(handle: Handle<TabsProps>): () => RemixNode {
180
+ return () => {
181
+ let {
182
+ activeTab,
183
+ children,
184
+ defaultActiveTab,
185
+ disabled,
186
+ mix,
187
+ onActiveTabChange,
188
+ size = 'md',
189
+ ...divProps
190
+ } = handle.props
191
+
192
+ return (
193
+ <tabs.Context
194
+ activeTab={activeTab}
195
+ defaultActiveTab={defaultActiveTab}
196
+ disabled={disabled}
197
+ onActiveTabChange={onActiveTabChange}
198
+ >
199
+ <div {...divProps} mix={[rootStyle, sizeStyles[size], tabs.root(), mix]}>
200
+ {children}
201
+ </div>
202
+ </tabs.Context>
203
+ )
204
+ }
205
+ }
206
+
207
+ export function TabList(handle: Handle<TabListProps>): () => RemixNode {
208
+ return () => {
209
+ let { children, mix, ...divProps } = handle.props
210
+
211
+ return (
212
+ <div {...divProps} mix={[listStyle, tabs.list(), mix]}>
213
+ {children}
214
+ </div>
215
+ )
216
+ }
217
+ }
218
+
219
+ export function Tab(handle: Handle<TabProps>): () => RemixNode {
220
+ return () => {
221
+ let { children, disabled, mix, name, type, ...buttonProps } = handle.props
222
+
223
+ return (
224
+ <button
225
+ {...buttonProps}
226
+ mix={[tabStyle, tabs.tab({ disabled, name }), mix]}
227
+ type={type ?? 'button'}
228
+ >
229
+ {children}
230
+ </button>
231
+ )
232
+ }
233
+ }
234
+
235
+ export function TabPanel(handle: Handle<TabPanelProps>): () => RemixNode {
236
+ return () => {
237
+ let { children, mix, name, ...divProps } = handle.props
238
+
239
+ return (
240
+ <div {...divProps} mix={[panelStyle, tabs.panel({ name }), mix]}>
241
+ {children}
242
+ </div>
243
+ )
244
+ }
245
+ }