@refraktor/core 0.0.1 → 0.0.3

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 (290) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/build/components/breadcrumbs/breadcrumbs.d.ts +4 -0
  3. package/build/components/breadcrumbs/breadcrumbs.d.ts.map +1 -0
  4. package/build/components/breadcrumbs/breadcrumbs.js +64 -0
  5. package/build/components/breadcrumbs/breadcrumbs.styles.d.ts +12 -0
  6. package/build/components/breadcrumbs/breadcrumbs.styles.d.ts.map +1 -0
  7. package/build/components/breadcrumbs/breadcrumbs.styles.js +43 -0
  8. package/build/components/breadcrumbs/breadcrumbs.test.d.ts +2 -0
  9. package/build/components/breadcrumbs/breadcrumbs.test.d.ts.map +1 -0
  10. package/build/components/breadcrumbs/breadcrumbs.test.js +72 -0
  11. package/build/components/breadcrumbs/breadcrumbs.types.d.ts +56 -0
  12. package/build/components/breadcrumbs/breadcrumbs.types.d.ts.map +1 -0
  13. package/build/components/breadcrumbs/breadcrumbs.types.js +1 -0
  14. package/build/components/breadcrumbs/breadcrumbs.utils.d.ts +10 -0
  15. package/build/components/breadcrumbs/breadcrumbs.utils.d.ts.map +1 -0
  16. package/build/components/breadcrumbs/breadcrumbs.utils.js +36 -0
  17. package/build/components/breadcrumbs/index.d.ts +3 -0
  18. package/build/components/breadcrumbs/index.d.ts.map +1 -0
  19. package/build/components/breadcrumbs/index.js +1 -0
  20. package/build/components/drawer/drawer-close/drawer-close.d.ts +4 -0
  21. package/build/components/drawer/drawer-close/drawer-close.d.ts.map +1 -0
  22. package/build/components/drawer/drawer-close/drawer-close.js +19 -0
  23. package/build/components/drawer/drawer-close/index.d.ts +2 -0
  24. package/build/components/drawer/drawer-close/index.d.ts.map +1 -0
  25. package/build/components/drawer/drawer-close/index.js +1 -0
  26. package/build/components/drawer/drawer-content/drawer-content.d.ts +4 -0
  27. package/build/components/drawer/drawer-content/drawer-content.d.ts.map +1 -0
  28. package/build/components/drawer/drawer-content/drawer-content.js +41 -0
  29. package/build/components/drawer/drawer-content/index.d.ts +2 -0
  30. package/build/components/drawer/drawer-content/index.d.ts.map +1 -0
  31. package/build/components/drawer/drawer-content/index.js +1 -0
  32. package/build/components/drawer/drawer-header/drawer-header.d.ts +4 -0
  33. package/build/components/drawer/drawer-header/drawer-header.d.ts.map +1 -0
  34. package/build/components/drawer/drawer-header/drawer-header.js +13 -0
  35. package/build/components/drawer/drawer-header/index.d.ts +2 -0
  36. package/build/components/drawer/drawer-header/index.d.ts.map +1 -0
  37. package/build/components/drawer/drawer-header/index.js +1 -0
  38. package/build/components/drawer/drawer-overlay/drawer-overlay.d.ts +4 -0
  39. package/build/components/drawer/drawer-overlay/drawer-overlay.d.ts.map +1 -0
  40. package/build/components/drawer/drawer-overlay/drawer-overlay.js +31 -0
  41. package/build/components/drawer/drawer-overlay/index.d.ts +2 -0
  42. package/build/components/drawer/drawer-overlay/index.d.ts.map +1 -0
  43. package/build/components/drawer/drawer-overlay/index.js +1 -0
  44. package/build/components/drawer/drawer-root/drawer-root.d.ts +4 -0
  45. package/build/components/drawer/drawer-root/drawer-root.d.ts.map +1 -0
  46. package/build/components/drawer/drawer-root/drawer-root.js +50 -0
  47. package/build/components/drawer/drawer-root/index.d.ts +2 -0
  48. package/build/components/drawer/drawer-root/index.d.ts.map +1 -0
  49. package/build/components/drawer/drawer-root/index.js +1 -0
  50. package/build/components/drawer/drawer.context.d.ts +23 -0
  51. package/build/components/drawer/drawer.context.d.ts.map +1 -0
  52. package/build/components/drawer/drawer.context.js +2 -0
  53. package/build/components/drawer/drawer.d.ts +4 -0
  54. package/build/components/drawer/drawer.d.ts.map +1 -0
  55. package/build/components/drawer/drawer.js +19 -0
  56. package/build/components/drawer/drawer.styles.d.ts +6 -0
  57. package/build/components/drawer/drawer.styles.d.ts.map +1 -0
  58. package/build/components/drawer/drawer.styles.js +21 -0
  59. package/build/components/drawer/drawer.test.d.ts +2 -0
  60. package/build/components/drawer/drawer.test.d.ts.map +1 -0
  61. package/build/components/drawer/drawer.test.js +70 -0
  62. package/build/components/drawer/drawer.types.d.ts +116 -0
  63. package/build/components/drawer/drawer.types.d.ts.map +1 -0
  64. package/build/components/drawer/drawer.types.js +1 -0
  65. package/build/components/drawer/index.d.ts +8 -0
  66. package/build/components/drawer/index.d.ts.map +1 -0
  67. package/build/components/drawer/index.js +6 -0
  68. package/build/components/drawer/use-drawer.d.ts +17 -0
  69. package/build/components/drawer/use-drawer.d.ts.map +1 -0
  70. package/build/components/drawer/use-drawer.js +61 -0
  71. package/build/components/index.d.ts +4 -0
  72. package/build/components/index.d.ts.map +1 -1
  73. package/build/components/index.js +4 -0
  74. package/build/components/menu/menu-dropdown/menu-dropdown.d.ts.map +1 -1
  75. package/build/components/menu/menu-dropdown/menu-dropdown.js +3 -2
  76. package/build/components/menu/menu-sub-dropdown/menu-sub-dropdown.d.ts.map +1 -1
  77. package/build/components/menu/menu-sub-dropdown/menu-sub-dropdown.js +2 -1
  78. package/build/components/menu/use-menu.d.ts.map +1 -1
  79. package/build/components/menu/use-menu.js +2 -1
  80. package/build/components/modal/modal-close/modal-close.d.ts.map +1 -1
  81. package/build/components/modal/modal-close/modal-close.js +1 -1
  82. package/build/components/modal/modal-content/modal-content.d.ts.map +1 -1
  83. package/build/components/modal/modal-content/modal-content.js +1 -1
  84. package/build/components/modal/modal-header/modal-header.d.ts.map +1 -1
  85. package/build/components/modal/modal-header/modal-header.js +1 -1
  86. package/build/components/modal/modal-overlay/modal-overlay.d.ts.map +1 -1
  87. package/build/components/modal/modal-overlay/modal-overlay.js +10 -2
  88. package/build/components/modal/modal.test.js +16 -0
  89. package/build/components/modal/modal.types.d.ts +4 -0
  90. package/build/components/modal/modal.types.d.ts.map +1 -1
  91. package/build/components/number-input/number-input.d.ts.map +1 -1
  92. package/build/components/number-input/number-input.js +22 -15
  93. package/build/components/number-input/number-input.test.d.ts +2 -0
  94. package/build/components/number-input/number-input.test.d.ts.map +1 -0
  95. package/build/components/number-input/number-input.test.js +14 -0
  96. package/build/components/number-input/number-input.types.d.ts +2 -2
  97. package/build/components/number-input/number-input.types.d.ts.map +1 -1
  98. package/build/components/popover/popover-dropdown/popover-dropdown.d.ts.map +1 -1
  99. package/build/components/popover/popover-dropdown/popover-dropdown.js +2 -1
  100. package/build/components/popover/use-popover.d.ts.map +1 -1
  101. package/build/components/popover/use-popover.js +2 -1
  102. package/build/components/portal/portal.js +1 -1
  103. package/build/components/segmented-control/index.d.ts +3 -0
  104. package/build/components/segmented-control/index.d.ts.map +1 -0
  105. package/build/components/segmented-control/index.js +1 -0
  106. package/build/components/segmented-control/segmented-control.d.ts +4 -0
  107. package/build/components/segmented-control/segmented-control.d.ts.map +1 -0
  108. package/build/components/segmented-control/segmented-control.js +113 -0
  109. package/build/components/segmented-control/segmented-control.styles.d.ts +9 -0
  110. package/build/components/segmented-control/segmented-control.styles.d.ts.map +1 -0
  111. package/build/components/segmented-control/segmented-control.styles.js +28 -0
  112. package/build/components/segmented-control/segmented-control.test.d.ts +2 -0
  113. package/build/components/segmented-control/segmented-control.test.d.ts.map +1 -0
  114. package/build/components/segmented-control/segmented-control.test.js +81 -0
  115. package/build/components/segmented-control/segmented-control.types.d.ts +49 -0
  116. package/build/components/segmented-control/segmented-control.types.d.ts.map +1 -0
  117. package/build/components/segmented-control/segmented-control.types.js +1 -0
  118. package/build/components/select/select-dropdown/select-dropdown.d.ts.map +1 -1
  119. package/build/components/select/select-dropdown/select-dropdown.js +3 -2
  120. package/build/components/select/select-item/select-item.d.ts.map +1 -1
  121. package/build/components/select/select-item/select-item.js +1 -1
  122. package/build/components/select/select-root/select-root.d.ts.map +1 -1
  123. package/build/components/select/select-root/select-root.js +36 -6
  124. package/build/components/select/select-trigger/select-trigger.d.ts.map +1 -1
  125. package/build/components/select/select-trigger/select-trigger.js +1 -1
  126. package/build/components/select/select.context.d.ts +2 -0
  127. package/build/components/select/select.context.d.ts.map +1 -1
  128. package/build/components/select/select.test.js +17 -0
  129. package/build/components/select/select.types.d.ts +10 -0
  130. package/build/components/select/select.types.d.ts.map +1 -1
  131. package/build/components/select/use-select.d.ts.map +1 -1
  132. package/build/components/select/use-select.js +2 -1
  133. package/build/components/split-pane/index.d.ts +3 -0
  134. package/build/components/split-pane/index.d.ts.map +1 -0
  135. package/build/components/split-pane/index.js +1 -0
  136. package/build/components/split-pane/split-pane.d.ts +4 -0
  137. package/build/components/split-pane/split-pane.d.ts.map +1 -0
  138. package/build/components/split-pane/split-pane.js +201 -0
  139. package/build/components/split-pane/split-pane.styles.d.ts +3 -0
  140. package/build/components/split-pane/split-pane.styles.d.ts.map +1 -0
  141. package/build/components/split-pane/split-pane.styles.js +8 -0
  142. package/build/components/split-pane/split-pane.test.d.ts +2 -0
  143. package/build/components/split-pane/split-pane.test.d.ts.map +1 -0
  144. package/build/components/split-pane/split-pane.test.js +105 -0
  145. package/build/components/split-pane/split-pane.types.d.ts +51 -0
  146. package/build/components/split-pane/split-pane.types.d.ts.map +1 -0
  147. package/build/components/split-pane/split-pane.types.js +1 -0
  148. package/build/components/switch/switch.js +1 -1
  149. package/build/components/table/index.d.ts +9 -0
  150. package/build/components/table/index.d.ts.map +1 -0
  151. package/build/components/table/index.js +7 -0
  152. package/build/components/table/table-body/index.d.ts +2 -0
  153. package/build/components/table/table-body/index.d.ts.map +1 -0
  154. package/build/components/table/table-body/index.js +1 -0
  155. package/build/components/table/table-body/table-body.d.ts +4 -0
  156. package/build/components/table/table-body/table-body.d.ts.map +1 -0
  157. package/build/components/table/table-body/table-body.js +17 -0
  158. package/build/components/table/table-caption/index.d.ts +2 -0
  159. package/build/components/table/table-caption/index.d.ts.map +1 -0
  160. package/build/components/table/table-caption/index.js +1 -0
  161. package/build/components/table/table-caption/table-caption.d.ts +4 -0
  162. package/build/components/table/table-caption/table-caption.d.ts.map +1 -0
  163. package/build/components/table/table-caption/table-caption.js +13 -0
  164. package/build/components/table/table-cell/index.d.ts +2 -0
  165. package/build/components/table/table-cell/index.d.ts.map +1 -0
  166. package/build/components/table/table-cell/index.js +1 -0
  167. package/build/components/table/table-cell/table-cell.d.ts +4 -0
  168. package/build/components/table/table-cell/table-cell.d.ts.map +1 -0
  169. package/build/components/table/table-cell/table-cell.js +13 -0
  170. package/build/components/table/table-head/index.d.ts +2 -0
  171. package/build/components/table/table-head/index.d.ts.map +1 -0
  172. package/build/components/table/table-head/index.js +1 -0
  173. package/build/components/table/table-head/table-head.d.ts +4 -0
  174. package/build/components/table/table-head/table-head.d.ts.map +1 -0
  175. package/build/components/table/table-head/table-head.js +11 -0
  176. package/build/components/table/table-header-cell/index.d.ts +2 -0
  177. package/build/components/table/table-header-cell/index.d.ts.map +1 -0
  178. package/build/components/table/table-header-cell/index.js +1 -0
  179. package/build/components/table/table-header-cell/table-header-cell.d.ts +4 -0
  180. package/build/components/table/table-header-cell/table-header-cell.d.ts.map +1 -0
  181. package/build/components/table/table-header-cell/table-header-cell.js +13 -0
  182. package/build/components/table/table-row/index.d.ts +2 -0
  183. package/build/components/table/table-row/index.d.ts.map +1 -0
  184. package/build/components/table/table-row/index.js +1 -0
  185. package/build/components/table/table-row/table-row.d.ts +4 -0
  186. package/build/components/table/table-row/table-row.d.ts.map +1 -0
  187. package/build/components/table/table-row/table-row.js +11 -0
  188. package/build/components/table/table.context.d.ts +16 -0
  189. package/build/components/table/table.context.d.ts.map +1 -0
  190. package/build/components/table/table.context.js +2 -0
  191. package/build/components/table/table.d.ts +4 -0
  192. package/build/components/table/table.d.ts.map +1 -0
  193. package/build/components/table/table.js +46 -0
  194. package/build/components/table/table.styles.d.ts +16 -0
  195. package/build/components/table/table.styles.d.ts.map +1 -0
  196. package/build/components/table/table.styles.js +39 -0
  197. package/build/components/table/table.test.d.ts +2 -0
  198. package/build/components/table/table.test.d.ts.map +1 -0
  199. package/build/components/table/table.test.js +59 -0
  200. package/build/components/table/table.types.d.ts +113 -0
  201. package/build/components/table/table.types.d.ts.map +1 -0
  202. package/build/components/table/table.types.js +1 -0
  203. package/build/components/tabs/tabs-tab/tabs-tab.d.ts.map +1 -1
  204. package/build/components/tabs/tabs-tab/tabs-tab.js +0 -6
  205. package/build/components/tooltip/tooltip.d.ts.map +1 -1
  206. package/build/components/tooltip/tooltip.js +7 -3
  207. package/build/components/tooltip/use-tooltip.d.ts.map +1 -1
  208. package/build/components/tooltip/use-tooltip.js +2 -1
  209. package/build/components/transition/transition.d.ts.map +1 -1
  210. package/build/components/transition/transition.js +16 -12
  211. package/build/style.css +1 -1
  212. package/package.json +2 -2
  213. package/src/components/breadcrumbs/breadcrumbs.styles.ts +55 -0
  214. package/src/components/breadcrumbs/breadcrumbs.test.tsx +136 -0
  215. package/src/components/breadcrumbs/breadcrumbs.tsx +199 -0
  216. package/src/components/breadcrumbs/breadcrumbs.types.ts +78 -0
  217. package/src/components/breadcrumbs/breadcrumbs.utils.ts +70 -0
  218. package/src/components/breadcrumbs/index.ts +6 -0
  219. package/src/components/drawer/drawer-close/drawer-close.tsx +43 -0
  220. package/src/components/drawer/drawer-close/index.ts +1 -0
  221. package/src/components/drawer/drawer-content/drawer-content.tsx +98 -0
  222. package/src/components/drawer/drawer-content/index.ts +1 -0
  223. package/src/components/drawer/drawer-header/drawer-header.tsx +40 -0
  224. package/src/components/drawer/drawer-header/index.ts +1 -0
  225. package/src/components/drawer/drawer-overlay/drawer-overlay.tsx +86 -0
  226. package/src/components/drawer/drawer-overlay/index.ts +1 -0
  227. package/src/components/drawer/drawer-root/drawer-root.tsx +94 -0
  228. package/src/components/drawer/drawer-root/index.ts +1 -0
  229. package/src/components/drawer/drawer.context.ts +25 -0
  230. package/src/components/drawer/drawer.styles.ts +32 -0
  231. package/src/components/drawer/drawer.test.tsx +166 -0
  232. package/src/components/drawer/drawer.tsx +30 -0
  233. package/src/components/drawer/drawer.types.ts +158 -0
  234. package/src/components/drawer/index.ts +16 -0
  235. package/src/components/drawer/use-drawer.ts +101 -0
  236. package/src/components/index.ts +10 -6
  237. package/src/components/menu/menu-dropdown/menu-dropdown.tsx +4 -3
  238. package/src/components/menu/menu-sub-dropdown/menu-sub-dropdown.tsx +2 -0
  239. package/src/components/menu/use-menu.ts +2 -1
  240. package/src/components/modal/modal-close/modal-close.tsx +1 -5
  241. package/src/components/modal/modal-content/modal-content.tsx +3 -4
  242. package/src/components/modal/modal-header/modal-header.tsx +4 -2
  243. package/src/components/modal/modal-overlay/modal-overlay.tsx +66 -44
  244. package/src/components/modal/modal.test.tsx +124 -88
  245. package/src/components/modal/modal.types.ts +6 -0
  246. package/src/components/modal/use-modal.ts +101 -101
  247. package/src/components/number-input/number-input.test.tsx +22 -0
  248. package/src/components/number-input/number-input.tsx +79 -51
  249. package/src/components/number-input/number-input.types.ts +8 -8
  250. package/src/components/popover/popover-dropdown/popover-dropdown.tsx +2 -0
  251. package/src/components/popover/use-popover.ts +2 -1
  252. package/src/components/portal/portal.tsx +1 -1
  253. package/src/components/segmented-control/index.ts +6 -0
  254. package/src/components/segmented-control/segmented-control.styles.ts +37 -0
  255. package/src/components/segmented-control/segmented-control.test.tsx +152 -0
  256. package/src/components/segmented-control/segmented-control.tsx +245 -0
  257. package/src/components/segmented-control/segmented-control.types.ts +75 -0
  258. package/src/components/select/select-dropdown/select-dropdown.tsx +4 -3
  259. package/src/components/select/select-item/select-item.tsx +1 -2
  260. package/src/components/select/select-root/select-root.tsx +87 -11
  261. package/src/components/select/select-trigger/select-trigger.tsx +2 -0
  262. package/src/components/select/select.context.ts +2 -0
  263. package/src/components/select/select.test.tsx +35 -0
  264. package/src/components/select/select.types.ts +15 -0
  265. package/src/components/select/use-select.ts +2 -1
  266. package/src/components/switch/switch.tsx +1 -1
  267. package/src/components/table/index.ts +24 -0
  268. package/src/components/table/table-body/index.ts +1 -0
  269. package/src/components/table/table-body/table-body.tsx +37 -0
  270. package/src/components/table/table-caption/index.ts +1 -0
  271. package/src/components/table/table-caption/table-caption.tsx +32 -0
  272. package/src/components/table/table-cell/index.ts +1 -0
  273. package/src/components/table/table-cell/table-cell.tsx +33 -0
  274. package/src/components/table/table-head/index.ts +1 -0
  275. package/src/components/table/table-head/table-head.tsx +29 -0
  276. package/src/components/table/table-header-cell/index.ts +1 -0
  277. package/src/components/table/table-header-cell/table-header-cell.tsx +33 -0
  278. package/src/components/table/table-row/index.ts +1 -0
  279. package/src/components/table/table-row/table-row.tsx +30 -0
  280. package/src/components/table/table.context.ts +18 -0
  281. package/src/components/table/table.styles.ts +62 -0
  282. package/src/components/table/table.test.tsx +145 -0
  283. package/src/components/table/table.tsx +91 -0
  284. package/src/components/table/table.types.ts +145 -0
  285. package/src/components/tabs/tabs-tab/tabs-tab.tsx +0 -8
  286. package/src/components/tooltip/tooltip.tsx +7 -1
  287. package/src/components/tooltip/use-tooltip.ts +2 -1
  288. package/src/components/transition/transition.tsx +18 -14
  289. package/src/style.css +0 -1
  290. package/tsconfig.tsbuildinfo +1 -1
@@ -160,6 +160,7 @@ const MenuSubDropdown = factory<MenuSubDropdownFactoryPayload>(
160
160
  transition="fade"
161
161
  duration={150}
162
162
  mounted={submenuLevel.menu.opened}
163
+ style={{ position: "relative", zIndex: 1000 }}
163
164
  {...transitionProps}
164
165
  >
165
166
  <MenuLevelProvider value={submenuLevel}>
@@ -172,6 +173,7 @@ const MenuSubDropdown = factory<MenuSubDropdownFactoryPayload>(
172
173
  tabIndex={-1}
173
174
  style={{
174
175
  ...submenuLevel.menu.floatingStyles,
176
+ zIndex: 1000,
175
177
  scrollbarGutter: "auto",
176
178
  ...style
177
179
  }}
@@ -128,7 +128,8 @@ export function useMenu(options: UseMenuProps = {}): UseMenuReturn {
128
128
  open: isOpen,
129
129
  onOpenChange: setIsOpen,
130
130
  middleware,
131
- whileElementsMounted: autoUpdate
131
+ whileElementsMounted: autoUpdate,
132
+ strategy: "fixed"
132
133
  });
133
134
 
134
135
  const click = useClick(floating.context, {
@@ -25,11 +25,7 @@ const ModalClose = factory<ModalCloseFactoryPayload>(
25
25
  type={type}
26
26
  aria-label="Close"
27
27
  className={cx(
28
- "absolute right-4 top-4 inline-flex h-9 w-9 items-center justify-center rounded-full cursor-pointer border border-transparent",
29
- "text-base text-[var(--refraktor-text-secondary)] transition-all",
30
- "hover:border-[var(--refraktor-border)] hover:bg-[var(--refraktor-bg-subtle)] hover:text-[var(--refraktor-text)]",
31
- "focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--refraktor-primary)]",
32
- "active:scale-95",
28
+ "size-6 text-[var(--refraktor-text-secondary)] hover:text-[var(--refraktor-text)] cursor-pointer transition-colors",
33
29
  getStyles("close"),
34
30
  className
35
31
  )}
@@ -38,7 +38,7 @@ const ModalContent = factory<ModalContentFactoryPayload>(
38
38
  mounted={modal.opened}
39
39
  {...resolvedTransitionProps}
40
40
  className={cx(
41
- "fixed inset-0 z-50 grid place-items-center p-3 sm:p-6 pointer-events-none",
41
+ "fixed inset-0 z-50 grid place-items-center pointer-events-none",
42
42
  transitionClassName
43
43
  )}
44
44
  >
@@ -50,9 +50,8 @@ const ModalContent = factory<ModalContentFactoryPayload>(
50
50
  data-opened={modal.opened}
51
51
  style={style}
52
52
  className={cx(
53
- "pointer-events-auto relative z-50 w-full max-w-[36rem]",
54
- "border border-[var(--refraktor-border)] bg-[var(--refraktor-bg-elevated)] px-5 pb-5 pt-4 text-[var(--refraktor-text)] shadow-[0_30px_80px_-40px_rgba(0,0,0,0.75)] sm:px-6 sm:pb-6 sm:pt-5",
55
- "max-h-[calc(100vh-1.5rem)] max-h-[calc(100dvh-1.5rem)] overflow-y-auto refraktor-scrollbar",
53
+ "pointer-events-auto relative z-50 w-full max-w-md",
54
+ "border border-[var(--refraktor-border)] bg-[var(--refraktor-bg)] p-4 text-[var(--refraktor-text)] shadow-md",
56
55
  getRadius(radius),
57
56
  getStyles("content"),
58
57
  className
@@ -14,7 +14,7 @@ const ModalHeader = factory<ModalHeaderFactoryPayload>(
14
14
  <div
15
15
  ref={ref}
16
16
  className={cx(
17
- "mb-3 flex items-center justify-between gap-2.5",
17
+ "mb-4 flex items-center justify-between",
18
18
  getStyles("header"),
19
19
  className
20
20
  )}
@@ -27,7 +27,9 @@ const ModalHeader = factory<ModalHeaderFactoryPayload>(
27
27
  {text ?? children}
28
28
  </div>
29
29
 
30
- {withClose && <ModalClose className="static shrink-0 self-center" />}
30
+ {withClose && (
31
+ <ModalClose className="static shrink-0 self-center" />
32
+ )}
31
33
  </div>
32
34
  );
33
35
  }
@@ -1,12 +1,23 @@
1
- import { useTheme } from "../../../theme";
2
- import { factory } from "../../../utils";
3
- import { Portal } from "../../portal";
4
- import { Transition } from "../../transition";
5
- import { useModalContext } from "../modal.context";
6
- import { ModalOverlayFactoryPayload } from "../modal.types";
7
-
1
+ import { useTheme } from "../../../theme";
2
+ import { factory } from "../../../utils";
3
+ import { Portal } from "../../portal";
4
+ import { Transition } from "../../transition";
5
+ import { useModalContext } from "../modal.context";
6
+ import { ModalOverlayFactoryPayload } from "../modal.types";
7
+
8
8
  const ModalOverlay = factory<ModalOverlayFactoryPayload>(
9
- ({ closeOnClick = true, className, onMouseDown, ...props }, ref) => {
9
+ (
10
+ {
11
+ closeOnClick = true,
12
+ backgroundOpacity = 0.5,
13
+ blur = 0,
14
+ className,
15
+ onMouseDown,
16
+ style,
17
+ ...props
18
+ },
19
+ ref
20
+ ) => {
10
21
  const { cx } = useTheme();
11
22
  const {
12
23
  modal,
@@ -16,49 +27,60 @@ const ModalOverlay = factory<ModalOverlayFactoryPayload>(
16
27
  getStyles
17
28
  } = useModalContext();
18
29
 
19
- const handleMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
20
- onMouseDown?.(event);
21
-
22
- if (
23
- event.defaultPrevented ||
24
- !closeOnClick ||
25
- !closeOnClickOutside
26
- ) {
27
- return;
28
- }
29
-
30
- modal.close();
31
- };
32
-
33
- const overlayContent = (
34
- <Transition
35
- transition="fade"
36
- duration={150}
37
- mounted={modal.opened}
38
- {...transitionProps}
39
- >
30
+ const blurValue = typeof blur === "number" ? `${blur}px` : blur;
31
+ const backdropFilterValue =
32
+ blurValue !== "0" && blurValue !== "0px"
33
+ ? `blur(${blurValue})`
34
+ : undefined;
35
+
36
+ const handleMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
37
+ onMouseDown?.(event);
38
+
39
+ if (
40
+ event.defaultPrevented ||
41
+ !closeOnClick ||
42
+ !closeOnClickOutside
43
+ ) {
44
+ return;
45
+ }
46
+
47
+ modal.close();
48
+ };
49
+
50
+ const overlayContent = (
51
+ <Transition
52
+ transition="fade"
53
+ duration={150}
54
+ mounted={modal.opened}
55
+ {...transitionProps}
56
+ >
40
57
  <div
41
58
  ref={ref}
42
59
  aria-hidden="true"
43
60
  className={cx(
44
- "fixed inset-0 z-40 bg-gradient-to-b from-black/60 via-black/45 to-black/65 backdrop-blur-[2px]",
61
+ "fixed inset-0 z-40",
45
62
  getStyles("overlay"),
46
63
  className
47
64
  )}
65
+ style={{
66
+ backgroundColor: `rgba(0, 0, 0, ${backgroundOpacity})`,
67
+ backdropFilter: backdropFilterValue,
68
+ ...style
69
+ }}
48
70
  onMouseDown={handleMouseDown}
49
71
  {...props}
50
72
  />
51
- </Transition>
52
- );
53
-
54
- return withinPortal ? (
55
- <Portal>{overlayContent}</Portal>
56
- ) : (
57
- overlayContent
58
- );
59
- }
60
- );
61
-
62
- ModalOverlay.displayName = "@refraktor/core/Modal.Overlay";
63
-
64
- export default ModalOverlay;
73
+ </Transition>
74
+ );
75
+
76
+ return withinPortal ? (
77
+ <Portal>{overlayContent}</Portal>
78
+ ) : (
79
+ overlayContent
80
+ );
81
+ }
82
+ );
83
+
84
+ ModalOverlay.displayName = "@refraktor/core/Modal.Overlay";
85
+
86
+ export default ModalOverlay;
@@ -1,110 +1,146 @@
1
- import { describe, expect, it, vi } from "vitest";
2
- import { render, screen, userEvent, waitFor } from "../../vitest";
3
- import Modal from "./modal";
4
- import { ModalContent } from "./modal-content";
5
- import { ModalOverlay } from "./modal-overlay";
6
- import { ModalRoot } from "./modal-root";
7
-
8
- describe("@refraktor/core/Modal", () => {
9
- const transitionProps = {
10
- duration: 0,
11
- immediate: true
12
- } as const;
13
-
14
- it("renders with compound subcomponents and closes with header close button", async () => {
15
- const user = userEvent.setup();
16
-
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { render, screen, userEvent, waitFor } from "../../vitest";
3
+ import Modal from "./modal";
4
+ import { ModalContent } from "./modal-content";
5
+ import { ModalOverlay } from "./modal-overlay";
6
+ import { ModalRoot } from "./modal-root";
7
+
8
+ describe("@refraktor/core/Modal", () => {
9
+ const transitionProps = {
10
+ duration: 0,
11
+ immediate: true
12
+ } as const;
13
+
14
+ it("renders with compound subcomponents and closes with header close button", async () => {
15
+ const user = userEvent.setup();
16
+
17
+ await render(
18
+ <Modal defaultOpened transitionProps={transitionProps}>
19
+ <Modal.Overlay />
20
+
21
+ <Modal.Content>
22
+ <Modal.Header text="Delete item" />
23
+ <p>Are you sure?</p>
24
+ </Modal.Content>
25
+ </Modal>
26
+ );
27
+
28
+ expect(
29
+ await screen.findByRole("dialog", { name: "Delete item" })
30
+ ).toBeInTheDocument();
31
+
32
+ await user.click(screen.getByRole("button", { name: "Close" }));
33
+
34
+ await waitFor(() => {
35
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
36
+ });
37
+ });
38
+
39
+ it("calls onOpenedChange when clicking overlay in controlled mode", async () => {
40
+ const user = userEvent.setup();
41
+ const onOpenedChange = vi.fn();
42
+
43
+ await render(
44
+ <Modal
45
+ opened
46
+ onOpenedChange={onOpenedChange}
47
+ transitionProps={transitionProps}
48
+ >
49
+ <Modal.Overlay data-testid="overlay" />
50
+ <Modal.Content>Controlled modal</Modal.Content>
51
+ </Modal>
52
+ );
53
+
54
+ await user.click(await screen.findByTestId("overlay"));
55
+
56
+ expect(onOpenedChange).toHaveBeenCalledWith(false);
57
+ });
58
+
59
+ it("closes on Escape key", async () => {
60
+ const user = userEvent.setup();
61
+
62
+ await render(
63
+ <Modal defaultOpened transitionProps={transitionProps}>
64
+ <Modal.Content>Keyboard close</Modal.Content>
65
+ </Modal>
66
+ );
67
+
68
+ await screen.findByRole("dialog");
69
+
70
+ await user.keyboard("{Escape}");
71
+
72
+ await waitFor(() => {
73
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
74
+ });
75
+ });
76
+
77
+ it("supports standalone subcomponents with ModalRoot", async () => {
17
78
  await render(
18
- <Modal defaultOpened transitionProps={transitionProps}>
19
- <Modal.Overlay />
20
-
21
- <Modal.Content>
22
- <Modal.Header text="Delete item" />
23
- <p>Are you sure?</p>
24
- </Modal.Content>
25
- </Modal>
26
- );
27
-
28
- expect(
29
- await screen.findByRole("dialog", { name: "Delete item" })
30
- ).toBeInTheDocument();
31
-
32
- await user.click(screen.getByRole("button", { name: "Close" }));
79
+ <ModalRoot defaultOpened transitionProps={transitionProps}>
80
+ <ModalOverlay />
81
+ <ModalContent>Standalone composition</ModalContent>
82
+ </ModalRoot>
83
+ );
33
84
 
34
- await waitFor(() => {
35
- expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
36
- });
85
+ expect(await screen.findByRole("dialog")).toBeInTheDocument();
37
86
  });
38
87
 
39
- it("calls onOpenedChange when clicking overlay in controlled mode", async () => {
40
- const user = userEvent.setup();
41
- const onOpenedChange = vi.fn();
42
-
88
+ it("applies custom overlay background opacity and blur", async () => {
43
89
  await render(
44
- <Modal
45
- opened
46
- onOpenedChange={onOpenedChange}
47
- transitionProps={transitionProps}
48
- >
49
- <Modal.Overlay data-testid="overlay" />
50
- <Modal.Content>Controlled modal</Modal.Content>
90
+ <Modal defaultOpened transitionProps={transitionProps}>
91
+ <Modal.Overlay
92
+ data-testid="overlay"
93
+ backgroundOpacity={0.4}
94
+ blur={6}
95
+ />
96
+ <Modal.Content>Styled overlay</Modal.Content>
51
97
  </Modal>
52
98
  );
53
99
 
54
- await user.click(await screen.findByTestId("overlay"));
100
+ const overlay = await screen.findByTestId("overlay");
55
101
 
56
- expect(onOpenedChange).toHaveBeenCalledWith(false);
102
+ expect(overlay).toHaveStyle({
103
+ backgroundColor: "rgba(0, 0, 0, 0.4)",
104
+ backdropFilter: "blur(6px)"
105
+ });
57
106
  });
58
107
 
59
- it("closes on Escape key", async () => {
60
- const user = userEvent.setup();
61
-
108
+ it("does not set backdrop blur for zero blur", async () => {
62
109
  await render(
63
110
  <Modal defaultOpened transitionProps={transitionProps}>
64
- <Modal.Content>Keyboard close</Modal.Content>
111
+ <Modal.Overlay data-testid="overlay" blur={0} />
112
+ <Modal.Content>No blur</Modal.Content>
65
113
  </Modal>
66
114
  );
67
115
 
68
- await screen.findByRole("dialog");
116
+ const overlay = await screen.findByTestId("overlay");
69
117
 
70
- await user.keyboard("{Escape}");
71
-
72
- await waitFor(() => {
73
- expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
118
+ expect(overlay).toHaveStyle({
119
+ backgroundColor: "rgba(0, 0, 0, 0.5)"
74
120
  });
75
- });
76
-
77
- it("supports standalone subcomponents with ModalRoot", async () => {
78
- await render(
79
- <ModalRoot defaultOpened transitionProps={transitionProps}>
80
- <ModalOverlay />
81
- <ModalContent>Standalone composition</ModalContent>
82
- </ModalRoot>
83
- );
84
-
85
- expect(await screen.findByRole("dialog")).toBeInTheDocument();
121
+ expect(overlay.style.backdropFilter).toBe("");
86
122
  });
87
123
 
88
124
  it("locks and unlocks body scroll when enabled", async () => {
89
125
  const user = userEvent.setup();
90
-
91
- await render(
92
- <Modal defaultOpened lockScroll transitionProps={transitionProps}>
93
- <Modal.Content>
94
- Scroll locked
95
- <Modal.Close />
96
- </Modal.Content>
97
- </Modal>
98
- );
99
-
100
- await waitFor(() => {
101
- expect(document.body).toHaveAttribute("data-scroll-locked");
102
- });
103
-
104
- await user.click(screen.getByRole("button", { name: "Close" }));
105
-
106
- await waitFor(() => {
107
- expect(document.body).not.toHaveAttribute("data-scroll-locked");
108
- });
109
- });
110
- });
126
+
127
+ await render(
128
+ <Modal defaultOpened lockScroll transitionProps={transitionProps}>
129
+ <Modal.Content>
130
+ Scroll locked
131
+ <Modal.Close />
132
+ </Modal.Content>
133
+ </Modal>
134
+ );
135
+
136
+ await waitFor(() => {
137
+ expect(document.body).toHaveAttribute("data-scroll-locked");
138
+ });
139
+
140
+ await user.click(screen.getByRole("button", { name: "Close" }));
141
+
142
+ await waitFor(() => {
143
+ expect(document.body).not.toHaveAttribute("data-scroll-locked");
144
+ });
145
+ });
146
+ });
@@ -64,6 +64,12 @@ export interface ModalOverlayProps extends ComponentPropsWithoutRef<"div"> {
64
64
  /** Whether clicking the overlay closes modal @default `true` */
65
65
  closeOnClick?: boolean;
66
66
 
67
+ /** Overlay background opacity @default `0.5` */
68
+ backgroundOpacity?: number;
69
+
70
+ /** Backdrop blur amount in px (or any CSS length) @default `0` */
71
+ blur?: number | string;
72
+
67
73
  /** Used for editing root class name */
68
74
  className?: string;
69
75
  }
@@ -1,101 +1,101 @@
1
- import { useUncontrolled } from "@refraktor/utils";
2
- import { useCallback, useEffect } from "react";
3
-
4
- interface UseModalProps {
5
- opened?: boolean;
6
- defaultOpened?: boolean;
7
- onOpenedChange?: (opened: boolean) => void;
8
- closeOnClickOutside?: boolean;
9
- closeOnEscape?: boolean;
10
- contentRef: React.MutableRefObject<HTMLElement | null>;
11
- }
12
-
13
- export interface UseModalReturn {
14
- opened: boolean;
15
- open: () => void;
16
- close: () => void;
17
- toggle: () => void;
18
- }
19
-
20
- export function useModal(options: UseModalProps): UseModalReturn {
21
- const {
22
- opened,
23
- defaultOpened,
24
- onOpenedChange,
25
- closeOnClickOutside = true,
26
- closeOnEscape = true,
27
- contentRef
28
- } = options;
29
-
30
- const [isOpen, setIsOpen] = useUncontrolled({
31
- value: opened,
32
- defaultValue: defaultOpened,
33
- finalValue: false,
34
- onChange: onOpenedChange
35
- });
36
-
37
- const open = useCallback(() => {
38
- setIsOpen(true);
39
- }, [setIsOpen]);
40
-
41
- const close = useCallback(() => {
42
- setIsOpen(false);
43
- }, [setIsOpen]);
44
-
45
- const toggle = useCallback(() => {
46
- setIsOpen(!isOpen);
47
- }, [isOpen, setIsOpen]);
48
-
49
- useEffect(() => {
50
- if (!isOpen || !closeOnEscape) {
51
- return;
52
- }
53
-
54
- const handleKeyDown = (event: KeyboardEvent) => {
55
- if (event.key === "Escape") {
56
- setIsOpen(false);
57
- }
58
- };
59
-
60
- document.addEventListener("keydown", handleKeyDown);
61
-
62
- return () => {
63
- document.removeEventListener("keydown", handleKeyDown);
64
- };
65
- }, [closeOnEscape, isOpen, setIsOpen]);
66
-
67
- useEffect(() => {
68
- if (!isOpen || !closeOnClickOutside) {
69
- return;
70
- }
71
-
72
- const handlePointerDown = (event: MouseEvent | TouchEvent) => {
73
- const target = event.target;
74
-
75
- if (!(target instanceof Node)) {
76
- return;
77
- }
78
-
79
- if (contentRef.current?.contains(target)) {
80
- return;
81
- }
82
-
83
- setIsOpen(false);
84
- };
85
-
86
- document.addEventListener("mousedown", handlePointerDown);
87
- document.addEventListener("touchstart", handlePointerDown);
88
-
89
- return () => {
90
- document.removeEventListener("mousedown", handlePointerDown);
91
- document.removeEventListener("touchstart", handlePointerDown);
92
- };
93
- }, [closeOnClickOutside, contentRef, isOpen, setIsOpen]);
94
-
95
- return {
96
- opened: isOpen,
97
- open,
98
- close,
99
- toggle
100
- };
101
- }
1
+ import { useUncontrolled } from "@refraktor/utils";
2
+ import { useCallback, useEffect } from "react";
3
+
4
+ interface UseModalProps {
5
+ opened?: boolean;
6
+ defaultOpened?: boolean;
7
+ onOpenedChange?: (opened: boolean) => void;
8
+ closeOnClickOutside?: boolean;
9
+ closeOnEscape?: boolean;
10
+ contentRef: React.MutableRefObject<HTMLElement | null>;
11
+ }
12
+
13
+ export interface UseModalReturn {
14
+ opened: boolean;
15
+ open: () => void;
16
+ close: () => void;
17
+ toggle: () => void;
18
+ }
19
+
20
+ export function useModal(options: UseModalProps): UseModalReturn {
21
+ const {
22
+ opened,
23
+ defaultOpened,
24
+ onOpenedChange,
25
+ closeOnClickOutside = true,
26
+ closeOnEscape = true,
27
+ contentRef
28
+ } = options;
29
+
30
+ const [isOpen, setIsOpen] = useUncontrolled({
31
+ value: opened,
32
+ defaultValue: defaultOpened,
33
+ finalValue: false,
34
+ onChange: onOpenedChange
35
+ });
36
+
37
+ const open = useCallback(() => {
38
+ setIsOpen(true);
39
+ }, [setIsOpen]);
40
+
41
+ const close = useCallback(() => {
42
+ setIsOpen(false);
43
+ }, [setIsOpen]);
44
+
45
+ const toggle = useCallback(() => {
46
+ setIsOpen(!isOpen);
47
+ }, [isOpen, setIsOpen]);
48
+
49
+ useEffect(() => {
50
+ if (!isOpen || !closeOnEscape) {
51
+ return;
52
+ }
53
+
54
+ const handleKeyDown = (event: KeyboardEvent) => {
55
+ if (event.key === "Escape") {
56
+ setIsOpen(false);
57
+ }
58
+ };
59
+
60
+ document.addEventListener("keydown", handleKeyDown);
61
+
62
+ return () => {
63
+ document.removeEventListener("keydown", handleKeyDown);
64
+ };
65
+ }, [closeOnEscape, isOpen, setIsOpen]);
66
+
67
+ useEffect(() => {
68
+ if (!isOpen || !closeOnClickOutside) {
69
+ return;
70
+ }
71
+
72
+ const handlePointerDown = (event: MouseEvent | TouchEvent) => {
73
+ const target = event.target;
74
+
75
+ if (!(target instanceof Node)) {
76
+ return;
77
+ }
78
+
79
+ if (contentRef.current?.contains(target)) {
80
+ return;
81
+ }
82
+
83
+ setIsOpen(false);
84
+ };
85
+
86
+ document.addEventListener("mousedown", handlePointerDown);
87
+ document.addEventListener("touchstart", handlePointerDown);
88
+
89
+ return () => {
90
+ document.removeEventListener("mousedown", handlePointerDown);
91
+ document.removeEventListener("touchstart", handlePointerDown);
92
+ };
93
+ }, [closeOnClickOutside, contentRef, isOpen, setIsOpen]);
94
+
95
+ return {
96
+ opened: isOpen,
97
+ open,
98
+ close,
99
+ toggle
100
+ };
101
+ }