@refraktor/core 0.0.3 → 0.0.4

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 (284) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/build/components/button/button.styles.js +5 -5
  3. package/build/components/chip/chip-group/chip-group.d.ts +4 -0
  4. package/build/components/chip/chip-group/chip-group.d.ts.map +1 -0
  5. package/build/components/chip/chip-group/chip-group.js +43 -0
  6. package/build/components/chip/chip-group/index.d.ts +2 -0
  7. package/build/components/chip/chip-group/index.d.ts.map +1 -0
  8. package/build/components/chip/chip-group/index.js +1 -0
  9. package/build/components/chip/chip.context.d.ts +15 -0
  10. package/build/components/chip/chip.context.d.ts.map +1 -0
  11. package/build/components/chip/chip.context.js +2 -0
  12. package/build/components/chip/chip.d.ts +4 -0
  13. package/build/components/chip/chip.d.ts.map +1 -0
  14. package/build/components/chip/chip.js +85 -0
  15. package/build/components/chip/chip.styles.d.ts +5 -0
  16. package/build/components/chip/chip.styles.d.ts.map +1 -0
  17. package/build/components/chip/chip.styles.js +19 -0
  18. package/build/components/chip/chip.test.d.ts +2 -0
  19. package/build/components/chip/chip.test.d.ts.map +1 -0
  20. package/build/components/chip/chip.test.js +107 -0
  21. package/build/components/chip/chip.types.d.ts +95 -0
  22. package/build/components/chip/chip.types.d.ts.map +1 -0
  23. package/build/components/chip/chip.types.js +1 -0
  24. package/build/components/chip/index.d.ts +4 -0
  25. package/build/components/chip/index.d.ts.map +1 -0
  26. package/build/components/chip/index.js +2 -0
  27. package/build/components/combobox/combobox-dropdown/combobox-dropdown.d.ts +4 -0
  28. package/build/components/combobox/combobox-dropdown/combobox-dropdown.d.ts.map +1 -0
  29. package/build/components/combobox/combobox-dropdown/combobox-dropdown.js +21 -0
  30. package/build/components/combobox/combobox-dropdown/index.d.ts +2 -0
  31. package/build/components/combobox/combobox-dropdown/index.d.ts.map +1 -0
  32. package/build/components/combobox/combobox-dropdown/index.js +1 -0
  33. package/build/components/combobox/combobox-group/combobox-group.d.ts +4 -0
  34. package/build/components/combobox/combobox-group/combobox-group.d.ts.map +1 -0
  35. package/build/components/combobox/combobox-group/combobox-group.js +15 -0
  36. package/build/components/combobox/combobox-group/index.d.ts +2 -0
  37. package/build/components/combobox/combobox-group/index.d.ts.map +1 -0
  38. package/build/components/combobox/combobox-group/index.js +1 -0
  39. package/build/components/combobox/combobox-input/combobox-input.d.ts +4 -0
  40. package/build/components/combobox/combobox-input/combobox-input.d.ts.map +1 -0
  41. package/build/components/combobox/combobox-input/combobox-input.js +101 -0
  42. package/build/components/combobox/combobox-input/index.d.ts +2 -0
  43. package/build/components/combobox/combobox-input/index.d.ts.map +1 -0
  44. package/build/components/combobox/combobox-input/index.js +1 -0
  45. package/build/components/combobox/combobox-option/combobox-option.d.ts +4 -0
  46. package/build/components/combobox/combobox-option/combobox-option.d.ts.map +1 -0
  47. package/build/components/combobox/combobox-option/combobox-option.js +86 -0
  48. package/build/components/combobox/combobox-option/index.d.ts +2 -0
  49. package/build/components/combobox/combobox-option/index.d.ts.map +1 -0
  50. package/build/components/combobox/combobox-option/index.js +1 -0
  51. package/build/components/combobox/combobox-root/combobox-root.d.ts +4 -0
  52. package/build/components/combobox/combobox-root/combobox-root.d.ts.map +1 -0
  53. package/build/components/combobox/combobox-root/combobox-root.js +282 -0
  54. package/build/components/combobox/combobox-root/index.d.ts +2 -0
  55. package/build/components/combobox/combobox-root/index.d.ts.map +1 -0
  56. package/build/components/combobox/combobox-root/index.js +1 -0
  57. package/build/components/combobox/combobox.context.d.ts +73 -0
  58. package/build/components/combobox/combobox.context.d.ts.map +1 -0
  59. package/build/components/combobox/combobox.context.js +50 -0
  60. package/build/components/combobox/combobox.d.ts +4 -0
  61. package/build/components/combobox/combobox.d.ts.map +1 -0
  62. package/build/components/combobox/combobox.js +31 -0
  63. package/build/components/combobox/combobox.test.d.ts +2 -0
  64. package/build/components/combobox/combobox.test.d.ts.map +1 -0
  65. package/build/components/combobox/combobox.test.js +104 -0
  66. package/build/components/combobox/combobox.types.d.ts +205 -0
  67. package/build/components/combobox/combobox.types.d.ts.map +1 -0
  68. package/build/components/combobox/combobox.types.js +1 -0
  69. package/build/components/combobox/index.d.ts +8 -0
  70. package/build/components/combobox/index.d.ts.map +1 -0
  71. package/build/components/combobox/index.js +6 -0
  72. package/build/components/combobox/use-combobox.d.ts +32 -0
  73. package/build/components/combobox/use-combobox.d.ts.map +1 -0
  74. package/build/components/combobox/use-combobox.js +80 -0
  75. package/build/components/drawer/drawer-body/drawer-body.d.ts +4 -0
  76. package/build/components/drawer/drawer-body/drawer-body.d.ts.map +1 -0
  77. package/build/components/drawer/drawer-body/drawer-body.js +11 -0
  78. package/build/components/drawer/drawer-body/index.d.ts +2 -0
  79. package/build/components/drawer/drawer-body/index.d.ts.map +1 -0
  80. package/build/components/drawer/drawer-body/index.js +1 -0
  81. package/build/components/drawer/drawer-content/drawer-content.d.ts.map +1 -1
  82. package/build/components/drawer/drawer-content/drawer-content.js +9 -6
  83. package/build/components/drawer/drawer-overlay/drawer-overlay.d.ts.map +1 -1
  84. package/build/components/drawer/drawer-overlay/drawer-overlay.js +4 -4
  85. package/build/components/drawer/drawer-root/drawer-root.d.ts.map +1 -1
  86. package/build/components/drawer/drawer-root/drawer-root.js +8 -9
  87. package/build/components/drawer/drawer.context.d.ts +2 -1
  88. package/build/components/drawer/drawer.context.d.ts.map +1 -1
  89. package/build/components/drawer/drawer.d.ts.map +1 -1
  90. package/build/components/drawer/drawer.js +5 -3
  91. package/build/components/drawer/drawer.test.js +55 -16
  92. package/build/components/drawer/drawer.types.d.ts +29 -3
  93. package/build/components/drawer/drawer.types.d.ts.map +1 -1
  94. package/build/components/drawer/index.d.ts +2 -1
  95. package/build/components/drawer/index.d.ts.map +1 -1
  96. package/build/components/drawer/index.js +1 -0
  97. package/build/components/drawer/use-drawer.d.ts +8 -1
  98. package/build/components/drawer/use-drawer.d.ts.map +1 -1
  99. package/build/components/drawer/use-drawer.js +25 -38
  100. package/build/components/file-input/file-input.d.ts +4 -0
  101. package/build/components/file-input/file-input.d.ts.map +1 -0
  102. package/build/components/file-input/file-input.js +88 -0
  103. package/build/components/file-input/file-input.test.d.ts +2 -0
  104. package/build/components/file-input/file-input.test.d.ts.map +1 -0
  105. package/build/components/file-input/file-input.test.js +74 -0
  106. package/build/components/file-input/file-input.types.d.ts +46 -0
  107. package/build/components/file-input/file-input.types.d.ts.map +1 -0
  108. package/build/components/file-input/file-input.types.js +1 -0
  109. package/build/components/file-input/file-input.utils.d.ts +11 -0
  110. package/build/components/file-input/file-input.utils.d.ts.map +1 -0
  111. package/build/components/file-input/file-input.utils.js +67 -0
  112. package/build/components/file-input/file-input.utils.test.d.ts +2 -0
  113. package/build/components/file-input/file-input.utils.test.d.ts.map +1 -0
  114. package/build/components/file-input/file-input.utils.test.js +27 -0
  115. package/build/components/file-input/index.d.ts +3 -0
  116. package/build/components/file-input/index.d.ts.map +1 -0
  117. package/build/components/file-input/index.js +2 -0
  118. package/build/components/for/for.d.ts +8 -0
  119. package/build/components/for/for.d.ts.map +1 -0
  120. package/build/components/for/for.js +32 -0
  121. package/build/components/for/for.test.d.ts +2 -0
  122. package/build/components/for/for.test.d.ts.map +1 -0
  123. package/build/components/for/for.test.js +31 -0
  124. package/build/components/for/for.types.d.ts +33 -0
  125. package/build/components/for/for.types.d.ts.map +1 -0
  126. package/build/components/for/for.types.js +1 -0
  127. package/build/components/for/index.d.ts +3 -0
  128. package/build/components/for/index.d.ts.map +1 -0
  129. package/build/components/for/index.js +1 -0
  130. package/build/components/index.d.ts +6 -0
  131. package/build/components/index.d.ts.map +1 -1
  132. package/build/components/index.js +6 -0
  133. package/build/components/modal/index.d.ts +2 -1
  134. package/build/components/modal/index.d.ts.map +1 -1
  135. package/build/components/modal/index.js +1 -0
  136. package/build/components/modal/modal-body/index.d.ts +2 -0
  137. package/build/components/modal/modal-body/index.d.ts.map +1 -0
  138. package/build/components/modal/modal-body/index.js +1 -0
  139. package/build/components/modal/modal-body/modal-body.d.ts +4 -0
  140. package/build/components/modal/modal-body/modal-body.d.ts.map +1 -0
  141. package/build/components/modal/modal-body/modal-body.js +11 -0
  142. package/build/components/modal/modal-content/modal-content.d.ts.map +1 -1
  143. package/build/components/modal/modal-content/modal-content.js +13 -5
  144. package/build/components/modal/modal-header/modal-header.js +2 -2
  145. package/build/components/modal/modal-overlay/modal-overlay.d.ts.map +1 -1
  146. package/build/components/modal/modal-overlay/modal-overlay.js +4 -4
  147. package/build/components/modal/modal-root/modal-root.d.ts.map +1 -1
  148. package/build/components/modal/modal-root/modal-root.js +12 -9
  149. package/build/components/modal/modal.context.d.ts +5 -2
  150. package/build/components/modal/modal.context.d.ts.map +1 -1
  151. package/build/components/modal/modal.d.ts.map +1 -1
  152. package/build/components/modal/modal.js +5 -3
  153. package/build/components/modal/modal.test.js +78 -13
  154. package/build/components/modal/modal.types.d.ts +34 -5
  155. package/build/components/modal/modal.types.d.ts.map +1 -1
  156. package/build/components/modal/use-modal.d.ts +8 -1
  157. package/build/components/modal/use-modal.d.ts.map +1 -1
  158. package/build/components/modal/use-modal.js +25 -38
  159. package/build/components/password-input/index.d.ts +3 -0
  160. package/build/components/password-input/index.d.ts.map +1 -0
  161. package/build/components/password-input/index.js +2 -0
  162. package/build/components/password-input/password-input.d.ts +4 -0
  163. package/build/components/password-input/password-input.d.ts.map +1 -0
  164. package/build/components/password-input/password-input.js +32 -0
  165. package/build/components/password-input/password-input.test.d.ts +2 -0
  166. package/build/components/password-input/password-input.test.d.ts.map +1 -0
  167. package/build/components/password-input/password-input.test.js +47 -0
  168. package/build/components/password-input/password-input.types.d.ts +24 -0
  169. package/build/components/password-input/password-input.types.d.ts.map +1 -0
  170. package/build/components/password-input/password-input.types.js +1 -0
  171. package/build/components/pin-input/index.d.ts +3 -0
  172. package/build/components/pin-input/index.d.ts.map +1 -0
  173. package/build/components/pin-input/index.js +2 -0
  174. package/build/components/pin-input/pin-input.d.ts +4 -0
  175. package/build/components/pin-input/pin-input.d.ts.map +1 -0
  176. package/build/components/pin-input/pin-input.js +245 -0
  177. package/build/components/pin-input/pin-input.test.d.ts +2 -0
  178. package/build/components/pin-input/pin-input.test.d.ts.map +1 -0
  179. package/build/components/pin-input/pin-input.test.js +87 -0
  180. package/build/components/pin-input/pin-input.types.d.ts +44 -0
  181. package/build/components/pin-input/pin-input.types.d.ts.map +1 -0
  182. package/build/components/pin-input/pin-input.types.js +1 -0
  183. package/build/components/scroll-area/index.d.ts +3 -0
  184. package/build/components/scroll-area/index.d.ts.map +1 -0
  185. package/build/components/scroll-area/index.js +1 -0
  186. package/build/components/scroll-area/scroll-area.d.ts +4 -0
  187. package/build/components/scroll-area/scroll-area.d.ts.map +1 -0
  188. package/build/components/scroll-area/scroll-area.js +30 -0
  189. package/build/components/scroll-area/scroll-area.test.d.ts +2 -0
  190. package/build/components/scroll-area/scroll-area.test.d.ts.map +1 -0
  191. package/build/components/scroll-area/scroll-area.test.js +39 -0
  192. package/build/components/scroll-area/scroll-area.types.d.ts +25 -0
  193. package/build/components/scroll-area/scroll-area.types.d.ts.map +1 -0
  194. package/build/components/scroll-area/scroll-area.types.js +1 -0
  195. package/build/components/segmented-control/segmented-control.d.ts.map +1 -1
  196. package/build/components/segmented-control/segmented-control.js +3 -3
  197. package/build/components/segmented-control/segmented-control.styles.js +13 -13
  198. package/build/components/segmented-control/segmented-control.test.js +11 -0
  199. package/build/components/segmented-control/segmented-control.types.d.ts +2 -0
  200. package/build/components/segmented-control/segmented-control.types.d.ts.map +1 -1
  201. package/build/icons/eye-off.d.ts +4 -0
  202. package/build/icons/eye-off.d.ts.map +1 -0
  203. package/build/icons/eye-off.js +5 -0
  204. package/build/icons/eye.d.ts +4 -0
  205. package/build/icons/eye.d.ts.map +1 -0
  206. package/build/icons/eye.js +5 -0
  207. package/build/icons/index.d.ts +2 -0
  208. package/build/icons/index.d.ts.map +1 -1
  209. package/build/icons/index.js +2 -0
  210. package/build/style.css +1 -1
  211. package/package.json +2 -2
  212. package/src/components/button/button.styles.ts +5 -5
  213. package/src/components/chip/chip-group/chip-group.tsx +107 -0
  214. package/src/components/chip/chip-group/index.ts +1 -0
  215. package/src/components/chip/chip.context.ts +15 -0
  216. package/src/components/chip/chip.styles.ts +36 -0
  217. package/src/components/chip/chip.test.tsx +197 -0
  218. package/src/components/chip/chip.tsx +208 -0
  219. package/src/components/chip/chip.types.ts +134 -0
  220. package/src/components/chip/index.ts +10 -0
  221. package/src/components/drawer/drawer-body/drawer-body.tsx +29 -0
  222. package/src/components/drawer/drawer-body/index.ts +1 -0
  223. package/src/components/drawer/drawer-content/drawer-content.tsx +63 -26
  224. package/src/components/drawer/drawer-overlay/drawer-overlay.tsx +6 -5
  225. package/src/components/drawer/drawer-root/drawer-root.tsx +17 -18
  226. package/src/components/drawer/drawer.context.ts +2 -1
  227. package/src/components/drawer/drawer.test.tsx +144 -36
  228. package/src/components/drawer/drawer.tsx +31 -3
  229. package/src/components/drawer/drawer.types.ts +37 -3
  230. package/src/components/drawer/index.ts +2 -0
  231. package/src/components/drawer/use-drawer.ts +44 -51
  232. package/src/components/file-input/file-input.test.tsx +134 -0
  233. package/src/components/file-input/file-input.tsx +224 -0
  234. package/src/components/file-input/file-input.types.ts +78 -0
  235. package/src/components/file-input/file-input.utils.test.ts +36 -0
  236. package/src/components/file-input/file-input.utils.ts +130 -0
  237. package/src/components/file-input/index.ts +2 -0
  238. package/src/components/for/for.test.tsx +66 -0
  239. package/src/components/for/for.tsx +53 -0
  240. package/src/components/for/for.types.ts +40 -0
  241. package/src/components/for/index.ts +2 -0
  242. package/src/components/index.ts +6 -0
  243. package/src/components/menu/menu-dropdown/menu-dropdown.tsx +220 -220
  244. package/src/components/menu/menu-sub-dropdown/menu-sub-dropdown.tsx +221 -221
  245. package/src/components/modal/index.ts +4 -1
  246. package/src/components/modal/modal-body/index.ts +1 -0
  247. package/src/components/modal/modal-body/modal-body.tsx +29 -0
  248. package/src/components/modal/modal-content/modal-content.tsx +71 -24
  249. package/src/components/modal/modal-header/modal-header.tsx +2 -2
  250. package/src/components/modal/modal-overlay/modal-overlay.tsx +46 -45
  251. package/src/components/modal/modal-root/modal-root.tsx +22 -17
  252. package/src/components/modal/modal.context.ts +5 -2
  253. package/src/components/modal/modal.test.tsx +234 -64
  254. package/src/components/modal/modal.tsx +36 -4
  255. package/src/components/modal/modal.types.ts +49 -8
  256. package/src/components/modal/use-modal.ts +44 -51
  257. package/src/components/password-input/index.ts +2 -0
  258. package/src/components/password-input/password-input.test.tsx +72 -0
  259. package/src/components/password-input/password-input.tsx +85 -0
  260. package/src/components/password-input/password-input.types.ts +30 -0
  261. package/src/components/pin-input/index.ts +2 -0
  262. package/src/components/pin-input/pin-input.test.tsx +149 -0
  263. package/src/components/pin-input/pin-input.tsx +473 -0
  264. package/src/components/pin-input/pin-input.types.ts +78 -0
  265. package/src/components/scroll-area/index.ts +6 -0
  266. package/src/components/scroll-area/scroll-area.test.tsx +72 -0
  267. package/src/components/scroll-area/scroll-area.tsx +70 -0
  268. package/src/components/scroll-area/scroll-area.types.ts +37 -0
  269. package/src/components/segmented-control/segmented-control.styles.ts +13 -13
  270. package/src/components/segmented-control/segmented-control.test.tsx +18 -0
  271. package/src/components/segmented-control/segmented-control.tsx +11 -1
  272. package/src/components/segmented-control/segmented-control.types.ts +3 -0
  273. package/src/components/select/select-dropdown/select-dropdown.tsx +299 -299
  274. package/src/components/select/select-root/select-root.tsx +333 -333
  275. package/src/components/select/select-trigger/select-trigger.tsx +123 -123
  276. package/src/components/select/select.context.ts +140 -140
  277. package/src/components/select/select.test.tsx +190 -190
  278. package/src/components/select/select.types.ts +272 -272
  279. package/src/components/select/use-select.ts +170 -170
  280. package/src/icons/eye-off.tsx +30 -0
  281. package/src/icons/eye.tsx +24 -0
  282. package/src/icons/index.ts +2 -0
  283. package/src/style.css +14 -8
  284. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,197 @@
1
+ import { createRef, useState } from "react";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ import { render, screen, userEvent } from "../../vitest";
4
+ import Chip from "./chip";
5
+
6
+ describe("@refraktor/core/Chip", () => {
7
+ it("renders correctly", async () => {
8
+ await render(<Chip>React</Chip>);
9
+
10
+ expect(screen.getByText("React")).toBeInTheDocument();
11
+ });
12
+
13
+ it("forwards ref correctly", async () => {
14
+ const ref = createRef<HTMLDivElement>();
15
+
16
+ await render(<Chip ref={ref}>React</Chip>);
17
+
18
+ expect(ref.current).toBeInstanceOf(HTMLDivElement);
19
+ expect(ref.current?.tagName).toBe("DIV");
20
+ });
21
+
22
+ it("supports uncontrolled selected state when selectable", async () => {
23
+ const user = userEvent.setup();
24
+
25
+ await render(<Chip selectable>React</Chip>);
26
+
27
+ const chip = screen.getByRole("button", { name: "React" });
28
+
29
+ expect(chip).toHaveAttribute("aria-pressed", "false");
30
+
31
+ await user.click(chip);
32
+
33
+ expect(chip).toHaveAttribute("aria-pressed", "true");
34
+ });
35
+
36
+ it("supports controlled selected state", async () => {
37
+ const user = userEvent.setup();
38
+
39
+ function Demo() {
40
+ const [selected, setSelected] = useState(false);
41
+
42
+ return (
43
+ <Chip selectable selected={selected} onSelectedChange={setSelected}>
44
+ React
45
+ </Chip>
46
+ );
47
+ }
48
+
49
+ await render(<Demo />);
50
+
51
+ const chip = screen.getByRole("button", { name: "React" });
52
+
53
+ await user.click(chip);
54
+
55
+ expect(chip).toHaveAttribute("aria-pressed", "true");
56
+ });
57
+
58
+ it("handles keyboard toggling", async () => {
59
+ const user = userEvent.setup();
60
+
61
+ await render(<Chip selectable>Vue</Chip>);
62
+
63
+ const chip = screen.getByRole("button", { name: "Vue" });
64
+ chip.focus();
65
+
66
+ await user.keyboard("{Space}");
67
+ expect(chip).toHaveAttribute("aria-pressed", "true");
68
+
69
+ await user.keyboard("{Enter}");
70
+ expect(chip).toHaveAttribute("aria-pressed", "false");
71
+ });
72
+
73
+ it("calls onRemove and does not toggle selection", async () => {
74
+ const user = userEvent.setup();
75
+ const onRemove = vi.fn();
76
+
77
+ await render(
78
+ <Chip selectable removable onRemove={onRemove} defaultSelected>
79
+ Svelte
80
+ </Chip>
81
+ );
82
+
83
+ const chip = screen.getByRole("button", { name: "Svelte" });
84
+ const removeButton = screen.getByRole("button", { name: "Remove chip" });
85
+
86
+ expect(chip).toHaveAttribute("aria-pressed", "true");
87
+
88
+ await user.click(removeButton);
89
+
90
+ expect(onRemove).toHaveBeenCalledTimes(1);
91
+ expect(chip).toHaveAttribute("aria-pressed", "false");
92
+ });
93
+
94
+ it("supports group selection", async () => {
95
+ const user = userEvent.setup();
96
+ const onChange = vi.fn();
97
+
98
+ await render(
99
+ <Chip.Group defaultValue={["react"]} onChange={onChange}>
100
+ <Chip value="react">React</Chip>
101
+ <Chip value="vue">Vue</Chip>
102
+ </Chip.Group>
103
+ );
104
+
105
+ const reactChip = screen.getByRole("button", { name: "React" });
106
+ const vueChip = screen.getByRole("button", { name: "Vue" });
107
+
108
+ expect(reactChip).toHaveAttribute("aria-pressed", "true");
109
+ expect(vueChip).toHaveAttribute("aria-pressed", "false");
110
+
111
+ await user.click(vueChip);
112
+ expect(onChange).toHaveBeenLastCalledWith(["react", "vue"]);
113
+
114
+ await user.click(reactChip);
115
+ expect(onChange).toHaveBeenLastCalledWith(["vue"]);
116
+ });
117
+
118
+ it("removes value from group with removable chip", async () => {
119
+ const user = userEvent.setup();
120
+ const onChange = vi.fn();
121
+
122
+ await render(
123
+ <Chip.Group defaultValue={["react"]} onChange={onChange}>
124
+ <Chip value="react" removable>
125
+ React
126
+ </Chip>
127
+ </Chip.Group>
128
+ );
129
+
130
+ await user.click(screen.getByRole("button", { name: "Remove chip" }));
131
+
132
+ expect(onChange).toHaveBeenLastCalledWith([]);
133
+ });
134
+
135
+ it("supports disabled state from group", async () => {
136
+ const user = userEvent.setup();
137
+ const onChange = vi.fn();
138
+
139
+ await render(
140
+ <Chip.Group disabled onChange={onChange}>
141
+ <Chip value="react">React</Chip>
142
+ </Chip.Group>
143
+ );
144
+
145
+ const chip = screen.getByRole("button", { name: "React" });
146
+ await user.click(chip);
147
+
148
+ expect(chip).toHaveAttribute("aria-disabled", "true");
149
+ expect(onChange).not.toHaveBeenCalled();
150
+ });
151
+
152
+ it("supports hidden inputs from group name", async () => {
153
+ const { container } = await render(
154
+ <Chip.Group name="frameworks" defaultValue={["react", "vue"]}>
155
+ <Chip value="react">React</Chip>
156
+ <Chip value="vue">Vue</Chip>
157
+ </Chip.Group>
158
+ );
159
+
160
+ const hiddenInputs = container.querySelectorAll(
161
+ 'input[type="hidden"][name="frameworks"]'
162
+ );
163
+
164
+ expect(hiddenInputs).toHaveLength(2);
165
+ expect(
166
+ Array.from(hiddenInputs).map(
167
+ (item) => (item as HTMLInputElement).value
168
+ )
169
+ ).toEqual(["react", "vue"]);
170
+ });
171
+
172
+ it("supports root and slot class names", async () => {
173
+ const { container } = await render(
174
+ <Chip
175
+ className="custom-root"
176
+ classNames={{
177
+ label: "custom-label",
178
+ removeButton: "custom-remove-button",
179
+ removeIcon: "custom-remove-icon"
180
+ }}
181
+ removable
182
+ >
183
+ React
184
+ </Chip>
185
+ );
186
+
187
+ const root = container.firstElementChild as HTMLDivElement;
188
+ const label = screen.getByText("React");
189
+ const removeButton = screen.getByRole("button", { name: "Remove chip" });
190
+ const removeIcon = removeButton.querySelector("span");
191
+
192
+ expect(root).toHaveClass("custom-root");
193
+ expect(label).toHaveClass("custom-label");
194
+ expect(removeButton).toHaveClass("custom-remove-button");
195
+ expect(removeIcon).toHaveClass("custom-remove-icon");
196
+ });
197
+ });
@@ -0,0 +1,208 @@
1
+ import { useId, useUncontrolled } from "@refraktor/utils";
2
+ import { KeyboardEvent } from "react";
3
+ import { XIcon } from "../../icons";
4
+ import { useTheme } from "../../theme";
5
+ import {
6
+ createClassNamesConfig,
7
+ createComponentConfig,
8
+ factory,
9
+ useClassNames,
10
+ useProps
11
+ } from "../../utils";
12
+ import { useChipGroupContext } from "./chip.context";
13
+ import { ChipGroup } from "./chip-group";
14
+ import { getSize, getVariant } from "./chip.styles";
15
+ import { ChipClassNames, ChipFactoryPayload, ChipProps } from "./chip.types";
16
+
17
+ const defaultProps = {
18
+ size: "sm",
19
+ radius: "full",
20
+ variant: "default",
21
+ selectable: false,
22
+ removable: false
23
+ } satisfies Partial<ChipProps>;
24
+
25
+ const Chip = factory<ChipFactoryPayload>((_props, ref) => {
26
+ const { cx, getRadius } = useTheme();
27
+ const {
28
+ id,
29
+ value,
30
+ children,
31
+ selected,
32
+ defaultSelected,
33
+ onSelectedChange,
34
+ selectable,
35
+ removable,
36
+ onRemove,
37
+ removeButtonLabel,
38
+ leftSection,
39
+ rightSection,
40
+ size,
41
+ radius,
42
+ variant,
43
+ disabled,
44
+ className,
45
+ classNames,
46
+ onClick,
47
+ onKeyDown,
48
+ ...props
49
+ } = useProps("Chip", defaultProps, _props);
50
+ const classes = useClassNames<ChipClassNames>("Chip", classNames);
51
+ const chipGroup = useChipGroupContext();
52
+
53
+ const _id = useId(id);
54
+
55
+ const [uncontrolledSelected, setUncontrolledSelected] =
56
+ useUncontrolled<boolean>({
57
+ value: selected,
58
+ defaultValue: defaultSelected,
59
+ finalValue: false,
60
+ onChange: onSelectedChange
61
+ });
62
+
63
+ const hasGroupValue = !!chipGroup && typeof value === "string";
64
+ const isSelectable = selectable || hasGroupValue;
65
+ const isRemovable = removable || typeof onRemove === "function";
66
+ const isDisabled = !!(disabled || chipGroup?.disabled);
67
+ const resolvedSize = size ?? chipGroup?.size ?? "sm";
68
+ const resolvedRadius = radius ?? chipGroup?.radius ?? "full";
69
+ const resolvedVariant = variant ?? chipGroup?.variant ?? "default";
70
+ const isSelected = hasGroupValue
71
+ ? chipGroup.value.includes(value)
72
+ : uncontrolledSelected;
73
+
74
+ const toggleChip = () => {
75
+ if (!isSelectable || isDisabled) {
76
+ return;
77
+ }
78
+
79
+ const nextSelected = !isSelected;
80
+
81
+ if (hasGroupValue) {
82
+ chipGroup.onValueChange(value, nextSelected);
83
+ return;
84
+ }
85
+
86
+ setUncontrolledSelected(nextSelected);
87
+ };
88
+
89
+ const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
90
+ onClick?.(event);
91
+
92
+ if (event.defaultPrevented) {
93
+ return;
94
+ }
95
+
96
+ toggleChip();
97
+ };
98
+
99
+ const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
100
+ onKeyDown?.(event);
101
+
102
+ if (event.defaultPrevented || isDisabled || !isSelectable) {
103
+ return;
104
+ }
105
+
106
+ if (event.key === "Enter" || event.key === " ") {
107
+ event.preventDefault();
108
+ toggleChip();
109
+ }
110
+ };
111
+
112
+ const handleRemove = (event: React.MouseEvent<HTMLButtonElement>) => {
113
+ event.stopPropagation();
114
+
115
+ if (isDisabled) {
116
+ return;
117
+ }
118
+
119
+ if (hasGroupValue) {
120
+ chipGroup.onValueChange(value, false);
121
+ } else if (isSelectable && isSelected) {
122
+ setUncontrolledSelected(false);
123
+ }
124
+
125
+ onRemove?.(event);
126
+ };
127
+
128
+ return (
129
+ <div
130
+ ref={ref}
131
+ id={_id}
132
+ data-selected={isSelected}
133
+ data-disabled={isDisabled}
134
+ data-selectable={isSelectable}
135
+ data-removable={isRemovable}
136
+ role={isSelectable ? "button" : undefined}
137
+ tabIndex={isSelectable ? (isDisabled ? -1 : 0) : undefined}
138
+ aria-pressed={isSelectable ? isSelected : undefined}
139
+ aria-disabled={isDisabled || undefined}
140
+ className={cx(
141
+ "inline-flex w-fit max-w-full items-center justify-center border select-none transition-colors",
142
+ "focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--refraktor-primary)]",
143
+ "data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50 data-[disabled=true]:pointer-events-none",
144
+ isSelectable ? "cursor-pointer" : "cursor-default",
145
+ getSize(resolvedSize),
146
+ getRadius(resolvedRadius),
147
+ getVariant(resolvedVariant, isSelected),
148
+ classes.root,
149
+ className
150
+ )}
151
+ onClick={handleClick}
152
+ onKeyDown={handleKeyDown}
153
+ {...props}
154
+ >
155
+ {leftSection && (
156
+ <span
157
+ className={cx(
158
+ "inline-flex shrink-0 items-center justify-center",
159
+ classes.leftSection
160
+ )}
161
+ aria-hidden="true"
162
+ >
163
+ {leftSection}
164
+ </span>
165
+ )}
166
+
167
+ <span className={cx("truncate", classes.label)}>{children}</span>
168
+
169
+ {rightSection && (
170
+ <span
171
+ className={cx(
172
+ "inline-flex shrink-0 items-center justify-center",
173
+ classes.rightSection
174
+ )}
175
+ aria-hidden="true"
176
+ >
177
+ {rightSection}
178
+ </span>
179
+ )}
180
+
181
+ {isRemovable && (
182
+ <button
183
+ type="button"
184
+ tabIndex={isDisabled ? -1 : 0}
185
+ aria-label={removeButtonLabel ?? "Remove chip"}
186
+ className={cx(
187
+ "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full border-0 bg-transparent p-0 cursor-pointer",
188
+ "focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--refraktor-primary)]",
189
+ classes.removeButton
190
+ )}
191
+ onClick={handleRemove}
192
+ disabled={isDisabled}
193
+ >
194
+ <span className={cx("inline-flex", classes.removeIcon)}>
195
+ <XIcon size={12} />
196
+ </span>
197
+ </button>
198
+ )}
199
+ </div>
200
+ );
201
+ });
202
+
203
+ Chip.displayName = "@refraktor/core/Chip";
204
+ Chip.configure = createComponentConfig<ChipProps>();
205
+ Chip.classNames = createClassNamesConfig<ChipClassNames>();
206
+ Chip.Group = ChipGroup;
207
+
208
+ export default Chip;
@@ -0,0 +1,134 @@
1
+ import { ComponentPropsWithoutRef, ReactNode } from "react";
2
+ import { RefraktorRadius, RefraktorSize } from "../../theme";
3
+ import {
4
+ createClassNamesConfig,
5
+ createComponentConfig,
6
+ FactoryPayload
7
+ } from "../../utils";
8
+ import { ChipGroup } from "./chip-group";
9
+
10
+ export type ChipVariant = "default" | "outline";
11
+ export type ChipGroupOrientation = "horizontal" | "vertical";
12
+
13
+ export type ChipClassNames = {
14
+ root?: string;
15
+ leftSection?: string;
16
+ label?: string;
17
+ rightSection?: string;
18
+ removeButton?: string;
19
+ removeIcon?: string;
20
+ };
21
+
22
+ export type ChipGroupClassNames = {
23
+ root?: string;
24
+ };
25
+
26
+ export interface ChipProps extends ComponentPropsWithoutRef<"div"> {
27
+ /** The value used by Chip.Group */
28
+ value?: string;
29
+
30
+ /** The selected state of the chip (controlled) */
31
+ selected?: boolean;
32
+
33
+ /** The initial selected state of the chip (uncontrolled) */
34
+ defaultSelected?: boolean;
35
+
36
+ /** Callback called when selected state changes */
37
+ onSelectedChange?: (selected: boolean) => void;
38
+
39
+ /** Whether chip can be toggled @default `false` */
40
+ selectable?: boolean;
41
+
42
+ /** Whether to show remove button @default `false` */
43
+ removable?: boolean;
44
+
45
+ /** Callback called when remove button is clicked */
46
+ onRemove?: (event: React.MouseEvent<HTMLButtonElement>) => void;
47
+
48
+ /** Accessible label for remove button */
49
+ removeButtonLabel?: string;
50
+
51
+ /** Content rendered at the start of the chip */
52
+ leftSection?: ReactNode;
53
+
54
+ /** Content rendered before remove button at the end of the chip */
55
+ rightSection?: ReactNode;
56
+
57
+ /** The size of the chip @default `sm` */
58
+ size?: RefraktorSize;
59
+
60
+ /** The radius of the chip @default `full` */
61
+ radius?: RefraktorRadius;
62
+
63
+ /** The variant of the chip @default `default` */
64
+ variant?: ChipVariant;
65
+
66
+ /** Whether chip is disabled @default `false` */
67
+ disabled?: boolean;
68
+
69
+ /** Used for editing root class name */
70
+ className?: string;
71
+
72
+ /** Used for styling different parts of the component */
73
+ classNames?: ChipClassNames;
74
+ }
75
+
76
+ export interface ChipGroupProps
77
+ extends Omit<ComponentPropsWithoutRef<"div">, "onChange"> {
78
+ /** Chip components to render */
79
+ children: ReactNode;
80
+
81
+ /** Selected values (controlled) */
82
+ value?: string[];
83
+
84
+ /** Initial selected values (uncontrolled) */
85
+ defaultValue?: string[];
86
+
87
+ /** Callback called when values change */
88
+ onChange?: (value: string[]) => void;
89
+
90
+ /** Hidden input name used for form submission */
91
+ name?: string;
92
+
93
+ /** Whether all chips in group are disabled */
94
+ disabled?: boolean;
95
+
96
+ /** Shared chip size */
97
+ size?: RefraktorSize;
98
+
99
+ /** Shared chip radius */
100
+ radius?: RefraktorRadius;
101
+
102
+ /** Shared chip variant */
103
+ variant?: ChipVariant;
104
+
105
+ /** Layout direction @default `horizontal` */
106
+ orientation?: ChipGroupOrientation;
107
+
108
+ /** Used for editing root class name */
109
+ className?: string;
110
+
111
+ /** Used for styling different parts of the component */
112
+ classNames?: ChipGroupClassNames;
113
+ }
114
+
115
+ export interface ChipFactoryPayload extends FactoryPayload {
116
+ props: ChipProps;
117
+ ref: HTMLDivElement;
118
+ compound: {
119
+ configure: ReturnType<typeof createComponentConfig<ChipProps>>;
120
+ classNames: ReturnType<typeof createClassNamesConfig<ChipClassNames>>;
121
+ Group: typeof ChipGroup;
122
+ };
123
+ }
124
+
125
+ export interface ChipGroupFactoryPayload extends FactoryPayload {
126
+ props: ChipGroupProps;
127
+ ref: HTMLDivElement;
128
+ compound: {
129
+ configure: ReturnType<typeof createComponentConfig<ChipGroupProps>>;
130
+ classNames: ReturnType<
131
+ typeof createClassNamesConfig<ChipGroupClassNames>
132
+ >;
133
+ };
134
+ }
@@ -0,0 +1,10 @@
1
+ export { default as Chip } from "./chip";
2
+ export { ChipGroup } from "./chip-group";
3
+ export type {
4
+ ChipProps,
5
+ ChipClassNames,
6
+ ChipVariant,
7
+ ChipGroupProps,
8
+ ChipGroupClassNames,
9
+ ChipGroupOrientation
10
+ } from "./chip.types";
@@ -0,0 +1,29 @@
1
+ import { useTheme } from "../../../theme";
2
+ import { factory } from "../../../utils";
3
+ import { useDrawerContext } from "../drawer.context";
4
+ import { DrawerBodyFactoryPayload } from "../drawer.types";
5
+
6
+ const DrawerBody = factory<DrawerBodyFactoryPayload>(
7
+ ({ children, className, ...props }, ref) => {
8
+ const { cx } = useTheme();
9
+ const { getStyles } = useDrawerContext();
10
+
11
+ return (
12
+ <div
13
+ ref={ref}
14
+ className={cx(
15
+ "overflow-y-auto",
16
+ getStyles("body"),
17
+ className
18
+ )}
19
+ {...props}
20
+ >
21
+ {children}
22
+ </div>
23
+ );
24
+ }
25
+ );
26
+
27
+ DrawerBody.displayName = "@refraktor/core/Drawer.Body";
28
+
29
+ export default DrawerBody;
@@ -0,0 +1 @@
1
+ export { default as DrawerBody } from "./drawer-body";