@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
@@ -0,0 +1,112 @@
1
+ import { createElement, css } from '@remix-run/ui'
2
+ import type { CSSMixinDescriptor, Handle, Props, RemixNode } from '@remix-run/ui'
3
+
4
+ import * as combobox from '@remix-run/ui/combobox/primitives'
5
+ import type { SearchValue } from '../shared/typeahead.ts'
6
+ import { CheckIcon } from '../shared/icons.tsx'
7
+ import {
8
+ listboxIndicatorStyle,
9
+ listboxLabelStyle,
10
+ listboxListStyle,
11
+ listboxOptionStyle,
12
+ popoverSurfaceStyle,
13
+ } from '../shared/listbox-popover-styles.ts'
14
+ import { componentStyleValues as styles } from '../shared/style-values.ts'
15
+
16
+ export interface ComboboxProps extends Omit<Props<'div'>, 'children'> {
17
+ children?: RemixNode
18
+ defaultValue?: string | null
19
+ disabled?: boolean
20
+ inputId?: string
21
+ name?: string
22
+ placeholder?: string
23
+ }
24
+
25
+ export interface ComboboxOptionProps extends Omit<Props<'div'>, 'children'> {
26
+ children?: RemixNode
27
+ disabled?: boolean
28
+ label: string
29
+ searchValue?: SearchValue
30
+ value: string
31
+ }
32
+
33
+ const comboboxPopoverCss: CSSMixinDescriptor = css({
34
+ opacity: 0,
35
+ '&:popover-open': {
36
+ opacity: 1,
37
+ },
38
+ '&:not(:popover-open)': {
39
+ pointerEvents: 'none',
40
+ },
41
+ '&[data-show-reason="nav"]:not(:popover-open)': {
42
+ transition: 'opacity 180ms ease-in, overlay 180ms ease-in, display 180ms ease-in',
43
+ transitionBehavior: 'allow-discrete',
44
+ },
45
+ '&[data-show-reason="hint"]:not(:popover-open)': {
46
+ transition: 'none',
47
+ transitionBehavior: 'normal',
48
+ },
49
+ })
50
+
51
+ const comboboxInputCss: CSSMixinDescriptor = css({
52
+ minHeight: styles.control.height.sm,
53
+ width: '100%',
54
+ paddingInline: styles.space.sm,
55
+ border: `0.5px solid ${styles.colors.border.default}`,
56
+ borderRadius: styles.radius.md,
57
+ backgroundColor: styles.surface.lvl0,
58
+ color: styles.colors.text.primary,
59
+ fontFamily: styles.fontFamily.sans,
60
+ fontSize: styles.fontSize.sm,
61
+ lineHeight: styles.lineHeight.normal,
62
+ boxShadow: 'inset 0 1px 0 light-dark(rgb(255 255 255 / 0.7), rgb(255 255 255 / 0.08))',
63
+ '&:focus-visible': {
64
+ outline: `2px solid ${styles.colors.focus.ring}`,
65
+ outlineOffset: styles.space.none,
66
+ },
67
+ '&[data-surface-visible="true"][aria-activedescendant]:focus-visible': {
68
+ outline: 'none',
69
+ },
70
+ })
71
+
72
+ export const inputStyle = comboboxInputCss
73
+ export const popoverStyle = comboboxPopoverCss
74
+
75
+ export function Combobox(handle: Handle<ComboboxProps>): () => RemixNode {
76
+ return () => {
77
+ let { children, defaultValue, disabled, inputId, name, placeholder, ...divProps } = handle.props
78
+
79
+ return (
80
+ <combobox.Context defaultValue={defaultValue} disabled={disabled} name={name}>
81
+ <div {...divProps}>
82
+ <input
83
+ defaultValue={defaultValue ?? undefined}
84
+ id={inputId}
85
+ mix={[inputStyle, combobox.input()]}
86
+ placeholder={placeholder}
87
+ />
88
+ <div mix={[popoverSurfaceStyle, popoverStyle, combobox.popover()]}>
89
+ <div mix={[listboxListStyle, combobox.list()]}>{children}</div>
90
+ </div>
91
+ {name && <input mix={combobox.hiddenInput()} />}
92
+ </div>
93
+ </combobox.Context>
94
+ )
95
+ }
96
+ }
97
+
98
+ export function ComboboxOption(handle: Handle<ComboboxOptionProps>): () => RemixNode {
99
+ return () => {
100
+ let { children, disabled, label, mix, searchValue, value, ...divProps } = handle.props
101
+
102
+ return (
103
+ <div
104
+ {...divProps}
105
+ mix={[listboxOptionStyle, combobox.option({ disabled, label, searchValue, value }), mix]}
106
+ >
107
+ <CheckIcon mix={listboxIndicatorStyle} />
108
+ <span mix={listboxLabelStyle}>{children ?? label}</span>
109
+ </div>
110
+ )
111
+ }
112
+ }
@@ -1,11 +1,8 @@
1
1
  import {
2
2
  attrs,
3
- css,
4
- createElement,
5
3
  createMixin,
6
4
  on,
7
5
  ref,
8
- type CSSMixinDescriptor,
9
6
  type Dispatched,
10
7
  type ElementProps,
11
8
  type Handle,
@@ -15,13 +12,11 @@ import {
15
12
  type RemixNode,
16
13
  } from '@remix-run/ui'
17
14
 
18
- import { Glyph } from '../glyph/glyph.tsx'
19
- import * as listbox from '../listbox/listbox.ts'
20
- import * as popover from '../popover/popover.ts'
21
- import { theme } from '../../theme/theme.ts'
22
- import { type SearchValue } from '../../interactions/typeahead/typeahead-mixin.ts'
23
- import { waitForCssTransition } from '../../utils/wait-for-css-transition.ts'
24
- import { wait } from '../../utils/wait.ts'
15
+ import * as listbox from '../listbox/index.ts'
16
+ import * as popover from '../popover/index.ts'
17
+ import { type SearchValue } from '../shared/typeahead.ts'
18
+ import { waitForCssTransition } from '../shared/wait-for-css-transition.ts'
19
+ import { wait } from '../shared/wait.ts'
25
20
 
26
21
  const COMBOBOX_CHANGE_EVENT = 'rmx:combobox-change' as const
27
22
  const INPUT_COMMIT_DELAY_MS = 50
@@ -33,48 +28,6 @@ type ComboboxChangeHandler<target extends HTMLElement> = (
33
28
 
34
29
  type ShowReason = 'hint' | 'nav'
35
30
 
36
- const comboboxPopoverCss: CSSMixinDescriptor = css({
37
- opacity: 0,
38
- '&:popover-open': {
39
- opacity: 1,
40
- },
41
- '&:not(:popover-open)': {
42
- pointerEvents: 'none',
43
- },
44
- '&[data-show-reason="nav"]:not(:popover-open)': {
45
- transition: 'opacity 180ms ease-in, overlay 180ms ease-in, display 180ms ease-in',
46
- transitionBehavior: 'allow-discrete',
47
- },
48
- '&[data-show-reason="hint"]:not(:popover-open)': {
49
- transition: 'none',
50
- transitionBehavior: 'normal',
51
- },
52
- })
53
-
54
- const comboboxInputCss: CSSMixinDescriptor = css({
55
- minHeight: theme.control.height.sm,
56
- width: '100%',
57
- paddingInline: theme.space.sm,
58
- border: `0.5px solid ${theme.colors.border.default}`,
59
- borderRadius: theme.radius.md,
60
- backgroundColor: theme.surface.lvl0,
61
- color: theme.colors.text.primary,
62
- fontFamily: theme.fontFamily.sans,
63
- fontSize: theme.fontSize.sm,
64
- lineHeight: theme.lineHeight.normal,
65
- boxShadow: 'inset 0 1px 0 rgb(255 255 255 / 0.7)',
66
- '&:focus-visible': {
67
- outline: `2px solid ${theme.colors.focus.ring}`,
68
- outlineOffset: theme.space.none,
69
- },
70
- '&[data-surface-visible="true"][aria-activedescendant]:focus-visible': {
71
- outline: 'none',
72
- },
73
- })
74
-
75
- export const inputStyle = comboboxInputCss
76
- export const popoverStyle = comboboxPopoverCss
77
-
78
31
  declare global {
79
32
  interface HTMLElementEventMap {
80
33
  [COMBOBOX_CHANGE_EVENT]: ComboboxChangeEvent
@@ -989,42 +942,3 @@ export function onComboboxChange<target extends HTMLElement>(
989
942
  ): ReturnType<typeof on<target, typeof COMBOBOX_CHANGE_EVENT>> {
990
943
  return on(COMBOBOX_CHANGE_EVENT, handler, captureBoolean)
991
944
  }
992
-
993
- export function Combobox(handle: Handle<ComboboxProps>): () => RemixNode {
994
- return () => {
995
- let { children, defaultValue, disabled, inputId, name, placeholder, ...divProps } = handle.props
996
-
997
- return (
998
- <combobox.Context defaultValue={defaultValue} disabled={disabled} name={name}>
999
- <div {...divProps}>
1000
- <input
1001
- defaultValue={defaultValue ?? undefined}
1002
- id={inputId}
1003
- mix={[inputStyle, combobox.input()]}
1004
- placeholder={placeholder}
1005
- />
1006
- <div mix={[popover.surfaceStyle, popoverStyle, combobox.popover()]}>
1007
- <div mix={[popover.contentStyle, listbox.listStyle, combobox.list()]}>{children}</div>
1008
- </div>
1009
- {name && <input mix={combobox.hiddenInput()} />}
1010
- </div>
1011
- </combobox.Context>
1012
- )
1013
- }
1014
- }
1015
-
1016
- export function ComboboxOption(handle: Handle<ComboboxOptionProps>): () => RemixNode {
1017
- return () => {
1018
- let { children, disabled, label, mix, searchValue, value, ...divProps } = handle.props
1019
-
1020
- return (
1021
- <div
1022
- {...divProps}
1023
- mix={[listbox.optionStyle, combobox.option({ disabled, label, searchValue, value }), mix]}
1024
- >
1025
- <Glyph mix={listbox.glyphStyle} name="check" />
1026
- <span mix={listbox.labelStyle}>{children ?? label}</span>
1027
- </div>
1028
- )
1029
- }
1030
- }
@@ -0,0 +1 @@
1
+ export { reconcileRoots, setComponentStalenessCheck } from '../runtime/refresh.ts'
package/src/index.ts CHANGED
@@ -35,7 +35,7 @@ export type {
35
35
  FrameHandle,
36
36
  FrameProps,
37
37
  } from './runtime/component.ts'
38
- export type { LoadModule, ResolveFrame } from './runtime/frame.ts'
38
+ export type { LoadModule, ResolveFrame, ResolveFrameOptions } from './runtime/frame.ts'
39
39
 
40
40
  // -- Elements/JSX/Props --
41
41
  export { createElement } from './runtime/create-element.ts'
@@ -0,0 +1,52 @@
1
+ # input
2
+
3
+ `input` is a style mixin for text inputs. Use `input()` directly on standalone native inputs, or compose `input.root()` with `input.field()` when the input needs inline icons or controls.
4
+
5
+ ## Primitive Usage
6
+
7
+ ```tsx
8
+ import input from 'remix/ui/input'
9
+
10
+ function ProductFilters() {
11
+ return () => (
12
+ <div>
13
+ <input mix={input()} placeholder="Limit" />
14
+
15
+ <div mix={input.root()}>
16
+ <SearchIcon />
17
+ <input mix={input.field()} placeholder="Search and filter products" />
18
+ </div>
19
+ </div>
20
+ )
21
+ }
22
+ ```
23
+
24
+ Compose app-owned styles when a field needs local layout or adornments:
25
+
26
+ ```tsx
27
+ import input from 'remix/ui/input'
28
+ import { filterFieldStyle, filterRootStyle } from './filters.styles'
29
+
30
+ function SearchFilter() {
31
+ return () => (
32
+ <div mix={[filterRootStyle, input.root()]}>
33
+ <SearchIcon />
34
+ <input mix={[filterFieldStyle, input.field()]} placeholder="Search" />
35
+ </div>
36
+ )
37
+ }
38
+ ```
39
+
40
+ ## `remix/ui/input`
41
+
42
+ - `input(options)`: styles a standalone native input. `size` may be `'md'` or `'lg'` and defaults to `'md'`.
43
+ - `input.root(options)`: styles a flex input frame for inline icons, buttons, and a child input.
44
+ - `input.field()`: styles the child native input inside `input.root()`.
45
+ - `InputOptions`: accepts `size`.
46
+ - `InputSize`: `'md'` or `'lg'`.
47
+
48
+ ## Behavior Notes
49
+
50
+ - `input.root()` uses child selectors to size direct SVG children as presentational icons.
51
+ - Put the icon before or after the field to control its visual position.
52
+ - Focus and disabled states work through the native input; the root mirrors them with `:focus-within` and `:has(input:disabled)`.
@@ -0,0 +1,147 @@
1
+ import { css } from '@remix-run/ui'
2
+ import type { CSSMixinDescriptor } from '@remix-run/ui'
3
+ import { controlFocusShadow } from '../shared/focus-styles.ts'
4
+ import type { CSSProps } from '../style/style.ts'
5
+
6
+ export type InputSize = 'md' | 'lg'
7
+
8
+ export interface InputOptions {
9
+ size?: InputSize
10
+ }
11
+
12
+ type InputMixin = readonly [CSSMixinDescriptor, CSSMixinDescriptor]
13
+
14
+ interface InputFunction {
15
+ (options?: InputOptions): InputMixin
16
+ root(options?: InputOptions): InputMixin
17
+ field(): CSSMixinDescriptor
18
+ }
19
+
20
+ const frameStyles = {
21
+ '--rmx-input-height': '32px',
22
+ '--rmx-input-padding-block': '6px',
23
+ '--rmx-input-padding-inline': '12px',
24
+ '--rmx-input-root-padding-inline': '8px',
25
+ '--rmx-input-gap': '6px',
26
+ '--rmx-input-icon-size': '16px',
27
+ '--rmx-input-icon-color': 'light-dark(#707070, #b3b3b3)',
28
+ appearance: 'none',
29
+ margin: 0,
30
+ boxSizing: 'border-box',
31
+ display: 'block',
32
+ width: '100%',
33
+ minWidth: 0,
34
+ height: 'var(--rmx-input-height)',
35
+ paddingBlock: 'var(--rmx-input-padding-block)',
36
+ paddingInline: 'var(--rmx-input-padding-inline)',
37
+ border: 0,
38
+ borderRadius: '8px',
39
+ background: 'light-dark(#FFFFFF, #1a1a1a)',
40
+ boxShadow:
41
+ '0 2px 3px -1px rgba(0, 0, 0, 0.04), 0 3px 4px -1.5px rgba(0, 0, 0, 0.04), 0 4px 5px -2px rgba(0, 0, 0, 0.04), 0 0 0 1px light-dark(rgba(0, 0, 0, 0.12), rgba(255, 255, 255, 0.2))',
42
+ color: 'light-dark(#101010, #ececec)',
43
+ fontFamily: '"Inter Variable", Inter, ui-sans-serif, system-ui, sans-serif',
44
+ fontStyle: 'normal',
45
+ fontWeight: 400,
46
+ fontSize: '13px',
47
+ lineHeight: '20px',
48
+ fontFeatureSettings: '"ss01" on, "cv01" on',
49
+ letterSpacing: 0,
50
+ textShadow: '0 1px 0 light-dark(#FFFFFF, rgb(0 0 0 / 0.35))',
51
+ '&::placeholder': {
52
+ color: 'light-dark(#B0B0B0, #777777)',
53
+ opacity: 1,
54
+ },
55
+ '&:disabled, &[aria-disabled="true"]': {
56
+ opacity: 0.55,
57
+ },
58
+ } as const satisfies CSSProps
59
+
60
+ const baseStyle: CSSMixinDescriptor = css({
61
+ ...frameStyles,
62
+ '&:focus-visible': {
63
+ outline: 0,
64
+ boxShadow: controlFocusShadow,
65
+ },
66
+ })
67
+
68
+ const rootBaseStyle: CSSMixinDescriptor = css({
69
+ ...frameStyles,
70
+ display: 'flex',
71
+ alignItems: 'center',
72
+ gap: 'var(--rmx-input-gap)',
73
+ paddingInline: 'var(--rmx-input-root-padding-inline)',
74
+ '&:focus-within': {
75
+ boxShadow: controlFocusShadow,
76
+ },
77
+ '&:has(input:disabled), &:has(input[aria-disabled="true"])': {
78
+ opacity: 0.55,
79
+ },
80
+ '& > svg': {
81
+ flex: 'none',
82
+ width: 'var(--rmx-input-icon-size)',
83
+ height: 'var(--rmx-input-icon-size)',
84
+ color: 'var(--rmx-input-icon-color)',
85
+ pointerEvents: 'none',
86
+ },
87
+ '& > button': {
88
+ flex: 'none',
89
+ },
90
+ })
91
+
92
+ const fieldBaseStyle: CSSMixinDescriptor = css({
93
+ appearance: 'none',
94
+ margin: 0,
95
+ boxSizing: 'border-box',
96
+ flex: '1 1 auto',
97
+ minWidth: 0,
98
+ width: '100%',
99
+ height: '20px',
100
+ padding: 0,
101
+ border: 0,
102
+ outline: 0,
103
+ background: 'transparent',
104
+ boxShadow: 'none',
105
+ color: 'light-dark(#101010, #ececec)',
106
+ font: 'inherit',
107
+ fontFeatureSettings: 'inherit',
108
+ letterSpacing: 'inherit',
109
+ textShadow: 'inherit',
110
+ '&::placeholder': {
111
+ color: 'light-dark(#B0B0B0, #777777)',
112
+ opacity: 1,
113
+ },
114
+ '&:disabled, &[aria-disabled="true"]': {
115
+ opacity: 1,
116
+ },
117
+ })
118
+
119
+ const sizeStyles = {
120
+ md: css({}),
121
+ lg: css({
122
+ '--rmx-input-height': '36px',
123
+ '--rmx-input-padding-block': '8px',
124
+ '--rmx-input-padding-inline': '14px',
125
+ '--rmx-input-root-padding-inline': '10px',
126
+ '--rmx-input-gap': '8px',
127
+ '--rmx-input-icon-size': '18px',
128
+ }),
129
+ } as const satisfies Record<InputSize, CSSMixinDescriptor>
130
+
131
+ function createInput(options: InputOptions = {}): InputMixin {
132
+ let { size = 'md' } = options
133
+ return [baseStyle, sizeStyles[size]]
134
+ }
135
+
136
+ function root(options: InputOptions = {}): InputMixin {
137
+ let { size = 'md' } = options
138
+ return [rootBaseStyle, sizeStyles[size]]
139
+ }
140
+
141
+ function field(): CSSMixinDescriptor {
142
+ return fieldBaseStyle
143
+ }
144
+
145
+ export const input: InputFunction = Object.assign(createInput, { root, field })
146
+
147
+ export default input
@@ -1,14 +1,14 @@
1
1
  # listbox
2
2
 
3
- `listbox` is a headless option-list primitive for controlled selection and highlighting. Use it under components like `select` and `combobox`, or directly when you need custom listbox markup.
3
+ `listbox` is a headless option-list primitive for controlled selection and highlighting. Use it under components like select and combobox, or directly when you need custom listbox markup.
4
4
 
5
- ## Usage
5
+ ## Primitive Usage
6
6
 
7
7
  ```tsx
8
8
  import type { Handle } from 'remix/ui'
9
- import { Glyph } from 'remix/ui/glyph'
10
9
  import * as listbox from 'remix/ui/listbox'
11
10
  import type { ListboxValue } from 'remix/ui/listbox'
11
+ import { listStyle, optionStyle } from './listbox.styles'
12
12
 
13
13
  function FrameworkListbox(handle: Handle) {
14
14
  let value: ListboxValue = 'remix'
@@ -27,11 +27,10 @@ function FrameworkListbox(handle: Handle) {
27
27
  void handle.update()
28
28
  }}
29
29
  >
30
- <div aria-label="Frameworks" tabIndex={0} mix={[listbox.listStyle, listbox.list()]}>
30
+ <div aria-label="Frameworks" tabIndex={0} mix={[listStyle, listbox.list()]}>
31
31
  {frameworks.map((option) => (
32
- <div key={option.value} mix={[listbox.optionStyle, listbox.option(option)]}>
33
- <Glyph mix={listbox.glyphStyle} name="check" />
34
- <span mix={listbox.labelStyle}>{option.label}</span>
32
+ <div key={option.value} mix={[optionStyle, listbox.option(option)]}>
33
+ {option.label}
35
34
  </div>
36
35
  ))}
37
36
  </div>
@@ -52,6 +51,7 @@ Use `textValue` when the visible label is not the best string for typeahead sear
52
51
  ```tsx
53
52
  <div
54
53
  mix={[
54
+ optionStyle,
55
55
  listbox.option({
56
56
  label: 'Staging',
57
57
  textValue: 'beta',
@@ -63,42 +63,13 @@ Use `textValue` when the visible label is not the best string for typeahead sear
63
63
  </div>
64
64
  ```
65
65
 
66
- Use `ref` when a parent component needs imperative coordination with the current option registry.
67
-
68
- ```tsx
69
- import type { ListboxRef } from 'remix/ui/listbox'
70
-
71
- let listboxRef: ListboxRef | undefined
72
-
73
- function selectLastOption() {
74
- listboxRef?.navigateLast()
75
- void listboxRef?.selectActive()
76
- }
77
-
78
- ;<listbox.Context
79
- value={value}
80
- activeValue={activeValue}
81
- ref={(ref) => {
82
- listboxRef = ref
83
- }}
84
- onSelect={(nextValue) => {
85
- value = nextValue
86
- }}
87
- onHighlight={(nextActiveValue) => {
88
- activeValue = nextActiveValue
89
- }}
90
- >
91
- {/* listbox markup */}
92
- </listbox.Context>
93
- ```
94
-
95
- ## `listbox.*`
66
+ ## `remix/ui/listbox`
96
67
 
97
68
  - `listbox.Context`: provider for controlled `value` and `activeValue`, option registration, selection, highlighting, optional ref access, `flashSelection`, `selectionFlashAttribute`, and `onSelectSettled`.
98
69
  - `listbox.list()`: mixin that wires `role="listbox"`, default `tabIndex={-1}`, keyboard navigation, focus scrolling, and typeahead highlighting.
99
70
  - `listbox.option(options)`: mixin that registers an option with required `label` and `value`, optional `disabled` and `textValue`, and wires `role="option"`, id, selected, disabled, highlighted, mouse, and click behavior.
100
- - `listStyle`, `optionStyle`, `glyphStyle`, and `labelStyle`: flat style mixins for standard listbox presentation.
101
71
  - `ListboxValue`: selected or active value, represented as `string | null`.
72
+ - `ListboxContext` and `ListboxProviderProps`: provider context and prop types for controlled listboxes.
102
73
  - `ListboxOption`: option input shape with `label`, `value`, optional `disabled`, and optional `textValue`.
103
74
  - `ListboxRegisteredOption`: registered option metadata passed to callbacks and refs.
104
75
  - `ListboxRef`: live ref object exposing active/selected options, option navigation, search matching, scrolling, and selection helpers.
@@ -108,8 +79,5 @@ function selectLastOption() {
108
79
  - Selection and highlighting are controlled. `onSelect` and `onHighlight` notify the parent, but DOM state updates after the parent rerenders with new values.
109
80
  - Disabled options are skipped by keyboard navigation, typeahead, mouse movement, and click selection.
110
81
  - Arrow keys wrap through enabled options. `Home` and `End` move to enabled boundaries. `Enter` and Space select the active option.
111
- - Mouse movement highlights enabled options. `mouseleave` clears the highlight when leaving the active option.
112
- - `Tab` is prevented and highlights the first enabled option.
113
82
  - Typeahead highlights the next matching enabled option without selecting it and supports `textValue`.
114
- - Focus and keyboard navigation scroll the active option into view with nearest-edge alignment.
115
83
  - `flashSelection` applies `selectionFlashAttribute` for 60ms, delays `onSelectSettled`, and ignores new highlight/select interactions until the flash completes.
@@ -1,21 +1,18 @@
1
1
  import {
2
2
  attrs,
3
3
  createMixin,
4
- css,
5
4
  on,
6
- type CSSMixinDescriptor,
7
5
  type ElementProps,
8
6
  type Handle,
9
7
  type MixinFactory,
10
8
  type RemixNode,
11
9
  } from '@remix-run/ui'
12
- import { theme } from '../../theme/theme.ts'
13
10
  import {
14
11
  hiddenTypeahead,
15
12
  matchNextItemBySearchText,
16
13
  type SearchValue,
17
- } from '../../interactions/typeahead/typeahead-mixin.ts'
18
- import { flashAttribute } from '../../utils/flash-attribute.ts'
14
+ } from '../shared/typeahead.ts'
15
+ import { flashAttribute } from './flash-attribute.ts'
19
16
 
20
17
  export type ListboxValue = string | null
21
18
 
@@ -69,88 +66,6 @@ export interface ListboxRegisteredOption extends ListboxOption {
69
66
 
70
67
  interface RegisteredOption extends ListboxRegisteredOption {}
71
68
 
72
- const listCss: CSSMixinDescriptor = css({
73
- display: 'flex',
74
- flexDirection: 'column',
75
- outline: 'none',
76
- userSelect: 'none',
77
- WebkitUserSelect: 'none',
78
- '--rmx-ui-item-inset': theme.space.sm,
79
- '--rmx-ui-item-indicator-gap': theme.space.xs,
80
- '--rmx-ui-item-indicator-width': theme.fontSize.sm,
81
- })
82
-
83
- const itemCss: CSSMixinDescriptor = css({
84
- display: 'grid',
85
- gridTemplateColumns: 'max-content minmax(0, 1fr)',
86
- alignItems: 'center',
87
- width: '100%',
88
- minHeight: theme.control.height.md,
89
- padding: `${theme.space.xs} ${theme.space.sm}`,
90
- borderRadius: theme.radius.md,
91
- backgroundColor: 'transparent',
92
- color: theme.colors.text.primary,
93
- fontFamily: theme.fontFamily.sans,
94
- fontSize: theme.fontSize.sm,
95
- fontWeight: theme.fontWeight.normal,
96
- lineHeight: theme.lineHeight.normal,
97
- textAlign: 'left',
98
- userSelect: 'none',
99
- WebkitUserSelect: 'none',
100
- '&:focus': {
101
- outline: 'none',
102
- },
103
- '&[data-highlighted="true"]': {
104
- backgroundColor: theme.colors.action.primary.background,
105
- color: theme.colors.action.primary.foreground,
106
- },
107
- '&[aria-disabled="true"]': {
108
- opacity: 0.5,
109
- },
110
- scrollMarginBlock: theme.space.xs,
111
- '--rmx-listbox-option-indicator-opacity': '0',
112
- '&[hidden]': {
113
- display: 'none',
114
- },
115
- '&[data-listbox-flash="true"], &[data-select-flash="true"], &[data-combobox-flash="true"]': {
116
- backgroundColor: 'transparent',
117
- color: theme.colors.text.primary,
118
- },
119
- '&[aria-selected="true"]': {
120
- '--rmx-listbox-option-indicator-opacity': '1',
121
- },
122
- })
123
-
124
- const itemGlyphCss: CSSMixinDescriptor = css({
125
- gridColumn: '1',
126
- display: 'inline-flex',
127
- alignItems: 'center',
128
- justifyContent: 'center',
129
- width: '1em',
130
- height: '1em',
131
- color: 'currentColor',
132
- flexShrink: 0,
133
- opacity: 'var(--rmx-listbox-option-indicator-opacity)',
134
- '& > svg': {
135
- display: 'block',
136
- width: '100%',
137
- height: '100%',
138
- },
139
- })
140
-
141
- const itemLabelCss: CSSMixinDescriptor = css({
142
- display: 'inline-flex',
143
- alignItems: 'center',
144
- minWidth: 0,
145
- paddingInline: theme.space.xs,
146
- WebkitUserSelect: 'none',
147
- })
148
-
149
- export const listStyle = listCss
150
- export const optionStyle = itemCss
151
- export const glyphStyle = itemGlyphCss
152
- export const labelStyle = itemLabelCss
153
-
154
69
  function ListboxProvider(handle: Handle<ListboxProviderProps, ListboxContext>): () => RemixNode {
155
70
  let options: RegisteredOption[] = []
156
71
  let state: State = 'idle'