@rojaostudio/ds 1.0.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 (291) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +89 -0
  3. package/brand/rojao-black-on-white.png +0 -0
  4. package/brand/rojao-black.png +0 -0
  5. package/brand/rojao-white-on-black.png +0 -0
  6. package/brand/rojao-white.png +0 -0
  7. package/dist/chunk-ORMEWXMH.js +37 -0
  8. package/dist/compat/generate.d.ts +6 -0
  9. package/dist/compat/generate.js +1 -0
  10. package/dist/compat/recipes.d.ts +1 -0
  11. package/dist/compat/recipes.js +1 -0
  12. package/dist/compat/themes.d.ts +1 -0
  13. package/dist/compat/themes.js +1 -0
  14. package/dist/compat/tokens.d.ts +1 -0
  15. package/dist/compat/tokens.js +1 -0
  16. package/dist/components/accordion.d.ts +35 -0
  17. package/dist/components/accordion.js +95 -0
  18. package/dist/components/alert.d.ts +24 -0
  19. package/dist/components/alert.js +72 -0
  20. package/dist/components/avatar.d.ts +45 -0
  21. package/dist/components/avatar.js +97 -0
  22. package/dist/components/badge.d.ts +45 -0
  23. package/dist/components/badge.js +114 -0
  24. package/dist/components/blocker-card.d.ts +42 -0
  25. package/dist/components/blocker-card.js +45 -0
  26. package/dist/components/bottom-sheet.d.ts +31 -0
  27. package/dist/components/bottom-sheet.js +120 -0
  28. package/dist/components/breadcrumb.d.ts +28 -0
  29. package/dist/components/breadcrumb.js +52 -0
  30. package/dist/components/button.d.ts +27 -0
  31. package/dist/components/button.js +124 -0
  32. package/dist/components/card.d.ts +27 -0
  33. package/dist/components/card.js +52 -0
  34. package/dist/components/chat-bubble.d.ts +16 -0
  35. package/dist/components/chat-bubble.js +55 -0
  36. package/dist/components/checkbox.d.ts +14 -0
  37. package/dist/components/checkbox.js +78 -0
  38. package/dist/components/chip-input.d.ts +26 -0
  39. package/dist/components/chip-input.js +182 -0
  40. package/dist/components/chips.d.ts +22 -0
  41. package/dist/components/chips.js +94 -0
  42. package/dist/components/choice-card.d.ts +16 -0
  43. package/dist/components/choice-card.js +60 -0
  44. package/dist/components/choice-carousel.d.ts +16 -0
  45. package/dist/components/choice-carousel.js +154 -0
  46. package/dist/components/choice-preview-card.d.ts +37 -0
  47. package/dist/components/choice-preview-card.js +39 -0
  48. package/dist/components/color-input.d.ts +20 -0
  49. package/dist/components/color-input.js +79 -0
  50. package/dist/components/combobox.d.ts +70 -0
  51. package/dist/components/combobox.js +213 -0
  52. package/dist/components/context-menu.d.ts +33 -0
  53. package/dist/components/context-menu.js +70 -0
  54. package/dist/components/copilot-hint.d.ts +18 -0
  55. package/dist/components/copilot-hint.js +63 -0
  56. package/dist/components/copy-field.d.ts +16 -0
  57. package/dist/components/copy-field.js +41 -0
  58. package/dist/components/currency-input.d.ts +32 -0
  59. package/dist/components/currency-input.js +138 -0
  60. package/dist/components/danger-zone.d.ts +20 -0
  61. package/dist/components/danger-zone.js +21 -0
  62. package/dist/components/data-table-header.d.ts +43 -0
  63. package/dist/components/data-table-header.js +205 -0
  64. package/dist/components/date-picker.d.ts +40 -0
  65. package/dist/components/date-picker.js +252 -0
  66. package/dist/components/divider.d.ts +20 -0
  67. package/dist/components/divider.js +47 -0
  68. package/dist/components/drawer.d.ts +26 -0
  69. package/dist/components/drawer.js +82 -0
  70. package/dist/components/dropzone.d.ts +19 -0
  71. package/dist/components/dropzone.js +65 -0
  72. package/dist/components/empty-state.d.ts +48 -0
  73. package/dist/components/empty-state.js +91 -0
  74. package/dist/components/fab.d.ts +38 -0
  75. package/dist/components/fab.js +100 -0
  76. package/dist/components/filter-chip.d.ts +54 -0
  77. package/dist/components/filter-chip.js +66 -0
  78. package/dist/components/floating-stepper.d.ts +44 -0
  79. package/dist/components/floating-stepper.js +53 -0
  80. package/dist/components/form-card-header.d.ts +13 -0
  81. package/dist/components/form-card-header.js +8 -0
  82. package/dist/components/icon-button.d.ts +17 -0
  83. package/dist/components/icon-button.js +80 -0
  84. package/dist/components/image-crop-modal.d.ts +59 -0
  85. package/dist/components/image-crop-modal.js +240 -0
  86. package/dist/components/image-upload.d.ts +72 -0
  87. package/dist/components/image-upload.js +271 -0
  88. package/dist/components/index.d.ts +85 -0
  89. package/dist/components/index.js +200 -0
  90. package/dist/components/input.d.ts +25 -0
  91. package/dist/components/input.js +136 -0
  92. package/dist/components/insight-card.d.ts +19 -0
  93. package/dist/components/insight-card.js +27 -0
  94. package/dist/components/label.d.ts +16 -0
  95. package/dist/components/label.js +43 -0
  96. package/dist/components/media-tile.d.ts +24 -0
  97. package/dist/components/media-tile.js +28 -0
  98. package/dist/components/menu.d.ts +50 -0
  99. package/dist/components/menu.js +80 -0
  100. package/dist/components/modal.d.ts +25 -0
  101. package/dist/components/modal.js +71 -0
  102. package/dist/components/notice.d.ts +50 -0
  103. package/dist/components/notice.js +103 -0
  104. package/dist/components/option-tile.d.ts +60 -0
  105. package/dist/components/option-tile.js +144 -0
  106. package/dist/components/page-shell.d.ts +29 -0
  107. package/dist/components/page-shell.js +36 -0
  108. package/dist/components/page-skeleton.d.ts +35 -0
  109. package/dist/components/page-skeleton.js +12 -0
  110. package/dist/components/page-tabs.d.ts +35 -0
  111. package/dist/components/page-tabs.js +55 -0
  112. package/dist/components/pagination.d.ts +31 -0
  113. package/dist/components/pagination.js +80 -0
  114. package/dist/components/paywall-banner.d.ts +37 -0
  115. package/dist/components/paywall-banner.js +42 -0
  116. package/dist/components/paywall.d.ts +44 -0
  117. package/dist/components/paywall.js +55 -0
  118. package/dist/components/phone-frame.d.ts +9 -0
  119. package/dist/components/phone-frame.js +18 -0
  120. package/dist/components/phone-input.d.ts +24 -0
  121. package/dist/components/phone-input.js +92 -0
  122. package/dist/components/pix-icon.d.ts +8 -0
  123. package/dist/components/pix-icon.js +24 -0
  124. package/dist/components/popover.d.ts +44 -0
  125. package/dist/components/popover.js +140 -0
  126. package/dist/components/pricing-card.d.ts +42 -0
  127. package/dist/components/pricing-card.js +29 -0
  128. package/dist/components/qr-display.d.ts +19 -0
  129. package/dist/components/qr-display.js +24 -0
  130. package/dist/components/radio.d.ts +33 -0
  131. package/dist/components/radio.js +97 -0
  132. package/dist/components/row-actions.d.ts +24 -0
  133. package/dist/components/row-actions.js +76 -0
  134. package/dist/components/saving-bar-context.d.ts +40 -0
  135. package/dist/components/saving-bar-context.js +125 -0
  136. package/dist/components/saving-bar.d.ts +18 -0
  137. package/dist/components/saving-bar.js +72 -0
  138. package/dist/components/search.d.ts +30 -0
  139. package/dist/components/search.js +81 -0
  140. package/dist/components/section-card.d.ts +14 -0
  141. package/dist/components/section-card.js +49 -0
  142. package/dist/components/section-header.d.ts +29 -0
  143. package/dist/components/section-header.js +7 -0
  144. package/dist/components/select.d.ts +21 -0
  145. package/dist/components/select.js +140 -0
  146. package/dist/components/selectable-card.d.ts +35 -0
  147. package/dist/components/selectable-card.js +27 -0
  148. package/dist/components/setting-row.d.ts +33 -0
  149. package/dist/components/setting-row.js +19 -0
  150. package/dist/components/settings-list.d.ts +25 -0
  151. package/dist/components/settings-list.js +22 -0
  152. package/dist/components/skeleton.d.ts +24 -0
  153. package/dist/components/skeleton.js +49 -0
  154. package/dist/components/slider.d.ts +32 -0
  155. package/dist/components/slider.js +79 -0
  156. package/dist/components/spinner.d.ts +14 -0
  157. package/dist/components/spinner.js +36 -0
  158. package/dist/components/step-progress.d.ts +12 -0
  159. package/dist/components/step-progress.js +24 -0
  160. package/dist/components/summary-bar.d.ts +31 -0
  161. package/dist/components/summary-bar.js +54 -0
  162. package/dist/components/table.d.ts +23 -0
  163. package/dist/components/table.js +80 -0
  164. package/dist/components/textarea.d.ts +21 -0
  165. package/dist/components/textarea.js +95 -0
  166. package/dist/components/themed.d.ts +36 -0
  167. package/dist/components/themed.js +22 -0
  168. package/dist/components/time-picker.d.ts +34 -0
  169. package/dist/components/time-picker.js +213 -0
  170. package/dist/components/toaster.d.ts +84 -0
  171. package/dist/components/toaster.js +284 -0
  172. package/dist/components/toggle-card-compact.d.ts +21 -0
  173. package/dist/components/toggle-card-compact.js +99 -0
  174. package/dist/components/toggle-card.d.ts +15 -0
  175. package/dist/components/toggle-card.js +76 -0
  176. package/dist/components/toggle-group.d.ts +67 -0
  177. package/dist/components/toggle-group.js +80 -0
  178. package/dist/components/toggle.d.ts +13 -0
  179. package/dist/components/toggle.js +64 -0
  180. package/dist/components/tooltip.d.ts +17 -0
  181. package/dist/components/tooltip.js +89 -0
  182. package/dist/components/typing-indicator.d.ts +8 -0
  183. package/dist/components/typing-indicator.js +27 -0
  184. package/dist/components/use-dismiss.d.ts +9 -0
  185. package/dist/components/use-dismiss.js +28 -0
  186. package/dist/components/use-focus-trap.d.ts +5 -0
  187. package/dist/components/use-focus-trap.js +54 -0
  188. package/dist/icons/index.d.ts +1 -0
  189. package/dist/icons/index.js +89 -0
  190. package/dist/targets/native/components/accordion.d.ts +18 -0
  191. package/dist/targets/native/components/accordion.js +122 -0
  192. package/dist/targets/native/components/alert.d.ts +16 -0
  193. package/dist/targets/native/components/alert.js +58 -0
  194. package/dist/targets/native/components/avatar.d.ts +25 -0
  195. package/dist/targets/native/components/avatar.js +88 -0
  196. package/dist/targets/native/components/badge.d.ts +27 -0
  197. package/dist/targets/native/components/badge.js +59 -0
  198. package/dist/targets/native/components/button.d.ts +18 -0
  199. package/dist/targets/native/components/button.js +84 -0
  200. package/dist/targets/native/components/card.d.ts +6 -0
  201. package/dist/targets/native/components/card.js +36 -0
  202. package/dist/targets/native/components/checkbox.d.ts +12 -0
  203. package/dist/targets/native/components/checkbox.js +59 -0
  204. package/dist/targets/native/components/chips.d.ts +17 -0
  205. package/dist/targets/native/components/chips.js +77 -0
  206. package/dist/targets/native/components/choice-card.d.ts +11 -0
  207. package/dist/targets/native/components/choice-card.js +52 -0
  208. package/dist/targets/native/components/context-menu.d.ts +11 -0
  209. package/dist/targets/native/components/context-menu.js +19 -0
  210. package/dist/targets/native/components/currency-input.d.ts +22 -0
  211. package/dist/targets/native/components/currency-input.js +105 -0
  212. package/dist/targets/native/components/danger-zone.d.ts +13 -0
  213. package/dist/targets/native/components/danger-zone.js +27 -0
  214. package/dist/targets/native/components/date-picker.d.ts +13 -0
  215. package/dist/targets/native/components/date-picker.js +185 -0
  216. package/dist/targets/native/components/divider.d.ts +9 -0
  217. package/dist/targets/native/components/divider.js +36 -0
  218. package/dist/targets/native/components/empty-state.d.ts +13 -0
  219. package/dist/targets/native/components/empty-state.js +10 -0
  220. package/dist/targets/native/components/fab.d.ts +25 -0
  221. package/dist/targets/native/components/fab.js +112 -0
  222. package/dist/targets/native/components/filter-chip.d.ts +22 -0
  223. package/dist/targets/native/components/filter-chip.js +70 -0
  224. package/dist/targets/native/components/form-field.d.ts +13 -0
  225. package/dist/targets/native/components/form-field.js +29 -0
  226. package/dist/targets/native/components/form-screen.d.ts +19 -0
  227. package/dist/targets/native/components/form-screen.js +88 -0
  228. package/dist/targets/native/components/google-icon.d.ts +8 -0
  229. package/dist/targets/native/components/google-icon.js +32 -0
  230. package/dist/targets/native/components/icon-button.d.ts +18 -0
  231. package/dist/targets/native/components/icon-button.js +80 -0
  232. package/dist/targets/native/components/icon.d.ts +11 -0
  233. package/dist/targets/native/components/icon.js +9 -0
  234. package/dist/targets/native/components/image-upload.d.ts +12 -0
  235. package/dist/targets/native/components/image-upload.js +95 -0
  236. package/dist/targets/native/components/index.d.ts +45 -0
  237. package/dist/targets/native/components/index.js +100 -0
  238. package/dist/targets/native/components/input.d.ts +17 -0
  239. package/dist/targets/native/components/input.js +103 -0
  240. package/dist/targets/native/components/list-item.d.ts +20 -0
  241. package/dist/targets/native/components/list-item.js +71 -0
  242. package/dist/targets/native/components/menu.d.ts +24 -0
  243. package/dist/targets/native/components/menu.js +71 -0
  244. package/dist/targets/native/components/modal.d.ts +15 -0
  245. package/dist/targets/native/components/modal.js +110 -0
  246. package/dist/targets/native/components/paywall-banner.d.ts +11 -0
  247. package/dist/targets/native/components/paywall-banner.js +46 -0
  248. package/dist/targets/native/components/paywall.d.ts +18 -0
  249. package/dist/targets/native/components/paywall.js +61 -0
  250. package/dist/targets/native/components/radio.d.ts +20 -0
  251. package/dist/targets/native/components/radio.js +71 -0
  252. package/dist/targets/native/components/search.d.ts +22 -0
  253. package/dist/targets/native/components/search.js +92 -0
  254. package/dist/targets/native/components/select.d.ts +17 -0
  255. package/dist/targets/native/components/select.js +86 -0
  256. package/dist/targets/native/components/sheet.d.ts +11 -0
  257. package/dist/targets/native/components/sheet.js +51 -0
  258. package/dist/targets/native/components/skeleton.d.ts +18 -0
  259. package/dist/targets/native/components/skeleton.js +52 -0
  260. package/dist/targets/native/components/slider.d.ts +18 -0
  261. package/dist/targets/native/components/slider.js +153 -0
  262. package/dist/targets/native/components/spinner.d.ts +7 -0
  263. package/dist/targets/native/components/spinner.js +10 -0
  264. package/dist/targets/native/components/stepper.d.ts +10 -0
  265. package/dist/targets/native/components/stepper.js +33 -0
  266. package/dist/targets/native/components/switch.d.ts +20 -0
  267. package/dist/targets/native/components/switch.js +68 -0
  268. package/dist/targets/native/components/text.d.ts +12 -0
  269. package/dist/targets/native/components/text.js +31 -0
  270. package/dist/targets/native/components/textarea.d.ts +13 -0
  271. package/dist/targets/native/components/textarea.js +92 -0
  272. package/dist/targets/native/components/theme.d.ts +18 -0
  273. package/dist/targets/native/components/theme.js +20 -0
  274. package/dist/targets/native/components/toaster.d.ts +35 -0
  275. package/dist/targets/native/components/toaster.js +159 -0
  276. package/dist/targets/native/fonts.d.ts +9 -0
  277. package/dist/targets/native/fonts.js +10 -0
  278. package/dist/targets/native/icons.d.ts +1 -0
  279. package/dist/targets/native/icons.js +1 -0
  280. package/dist/targets/native/index.d.ts +3 -0
  281. package/dist/targets/native/index.js +11 -0
  282. package/dist/targets/native/preset.cjs +69 -0
  283. package/dist/targets/native/resolve.d.ts +22 -0
  284. package/dist/targets/native/resolve.js +85 -0
  285. package/dist/targets/native/theme.css +118 -0
  286. package/dist/targets/native/theme.d.ts +117 -0
  287. package/dist/targets/native/theme.js +118 -0
  288. package/package.json +194 -0
  289. package/styles/_primitives.generated.css +284 -0
  290. package/styles/base.css +950 -0
  291. package/styles/themes/rojao.css +107 -0
@@ -0,0 +1,205 @@
1
+ "use client";
2
+ import "../chunk-ORMEWXMH.js";
3
+ import { useState } from "react";
4
+ import { ChevronDown, ListFilter, SlidersHorizontal, X } from "lucide-react";
5
+ import { FilterChip } from "./filter-chip.js";
6
+ import { Search } from "./search.js";
7
+ import { Divider } from "./divider.js";
8
+ import { IconButton } from "./icon-button.js";
9
+ import { Popover } from "./popover.js";
10
+ import { BottomSheet } from "./bottom-sheet.js";
11
+ const optCls = (selected) => `w-full text-left text-label px-3 py-1.5 rounded-(--radius-card) transition-colors flex items-center justify-between gap-2 ${selected ? "bg-brand-primary text-brand-on-primary" : "text-fg-secondary hover:bg-surface-raised"}`;
12
+ function triggerCls(isActive) {
13
+ const base = "h-control-md flex items-center gap-1 px-3 text-label font-medium rounded-(--radius-control) border transition-colors";
14
+ if (isActive) return `${base} border-brand-primary bg-brand-primary text-brand-on-primary`;
15
+ return `${base} border-stroke-default bg-surface-default text-fg-muted hover:bg-surface-raised hover:border-stroke-strong`;
16
+ }
17
+ function getOptionLabel(filter) {
18
+ var _a;
19
+ if (filter.value === "") return filter.label;
20
+ const opt = filter.options.find((o) => o.value === filter.value);
21
+ return (_a = opt == null ? void 0 : opt.label) != null ? _a : filter.label;
22
+ }
23
+ function FilterDropdown({ f, placement = "bottom-start" }) {
24
+ return /* @__PURE__ */ React.createElement(
25
+ Popover,
26
+ {
27
+ placement,
28
+ trigger: /* @__PURE__ */ React.createElement("button", { type: "button", className: triggerCls(f.value !== "") }, getOptionLabel(f), /* @__PURE__ */ React.createElement(ChevronDown, { size: 12 }))
29
+ },
30
+ ({ close }) => /* @__PURE__ */ React.createElement("div", { className: "w-36 rounded-(--radius-card) border border-stroke-default bg-surface-default shadow-xl p-1 overflow-hidden" }, f.options.map((opt) => /* @__PURE__ */ React.createElement(
31
+ "button",
32
+ {
33
+ key: opt.value,
34
+ type: "button",
35
+ onClick: () => {
36
+ f.onChange(opt.value);
37
+ close();
38
+ },
39
+ className: optCls(f.value === opt.value)
40
+ },
41
+ /* @__PURE__ */ React.createElement("span", null, opt.label),
42
+ opt.count != null && /* @__PURE__ */ React.createElement("span", { className: "text-[11px] font-semibold opacity-60 tabular-nums" }, opt.count)
43
+ )))
44
+ );
45
+ }
46
+ function MobileSingleFilter({ f }) {
47
+ const [open, setOpen] = useState(false);
48
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("button", { type: "button", className: triggerCls(f.value !== ""), onClick: () => setOpen(true) }, getOptionLabel(f), /* @__PURE__ */ React.createElement(ChevronDown, { size: 12 })), /* @__PURE__ */ React.createElement(BottomSheet, { open, onClose: () => setOpen(false), title: f.label }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-0.5" }, f.options.map((opt) => /* @__PURE__ */ React.createElement(
49
+ "button",
50
+ {
51
+ key: opt.value,
52
+ type: "button",
53
+ onClick: () => {
54
+ f.onChange(opt.value);
55
+ setOpen(false);
56
+ },
57
+ className: optCls(f.value === opt.value)
58
+ },
59
+ /* @__PURE__ */ React.createElement("span", null, opt.label),
60
+ opt.count != null && /* @__PURE__ */ React.createElement("span", { className: "text-[11px] font-semibold opacity-60 tabular-nums" }, opt.count)
61
+ )))));
62
+ }
63
+ function FiltersButton({ count, onClick }) {
64
+ return /* @__PURE__ */ React.createElement(
65
+ "button",
66
+ {
67
+ type: "button",
68
+ "data-filter-toggle": true,
69
+ onClick,
70
+ className: `h-control-md flex items-center gap-1.5 px-3 text-label border rounded-(--radius-control) transition-colors ${count > 0 ? "bg-brand-primary text-brand-on-primary border-brand-primary" : "bg-surface-default text-fg-muted border-stroke-default hover:bg-surface-raised"}`
71
+ },
72
+ /* @__PURE__ */ React.createElement(SlidersHorizontal, { size: 14 }),
73
+ "Filtros",
74
+ count > 0 && /* @__PURE__ */ React.createElement("span", { className: "inline-flex items-center justify-center w-4 h-4 rounded-full bg-surface-default text-fg-primary text-[10px] font-bold" }, count)
75
+ );
76
+ }
77
+ function FilterGroups({
78
+ filters,
79
+ onPick,
80
+ onClear,
81
+ showClear
82
+ }) {
83
+ return /* @__PURE__ */ React.createElement("div", { className: "space-y-4" }, filters.map((f) => /* @__PURE__ */ React.createElement("div", { key: f.key }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold text-fg-disabled uppercase tracking-wide mb-2" }, f.label), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-0.5" }, f.options.map((opt) => /* @__PURE__ */ React.createElement(
84
+ "button",
85
+ {
86
+ key: opt.value,
87
+ type: "button",
88
+ onClick: () => onPick(f, opt.value),
89
+ className: optCls(f.value === opt.value)
90
+ },
91
+ /* @__PURE__ */ React.createElement("span", null, opt.label),
92
+ opt.count != null && /* @__PURE__ */ React.createElement("span", { className: "text-[11px] font-semibold opacity-60 tabular-nums" }, opt.count)
93
+ ))))), onClear && showClear && /* @__PURE__ */ React.createElement(
94
+ "button",
95
+ {
96
+ type: "button",
97
+ onClick: onClear,
98
+ className: "w-full text-center text-caption text-fg-disabled hover:text-fg-secondary underline underline-offset-2 pt-1"
99
+ },
100
+ "Limpar filtros"
101
+ ));
102
+ }
103
+ function DataTableHeader({
104
+ search,
105
+ filters = [],
106
+ pillFilters = [],
107
+ onClear,
108
+ actions,
109
+ className = "",
110
+ mobileCollapse = false
111
+ }) {
112
+ var _a;
113
+ const [sheetOpen, setSheetOpen] = useState(false);
114
+ const activeFilterCount = filters.filter((f) => f.value !== "").length + pillFilters.filter((p) => p.active).length;
115
+ const collapseDesktop = filters.length >= 2;
116
+ const activeFilters = filters.filter((f) => f.value !== "");
117
+ const singleFilter = filters.length === 1 ? filters[0] : null;
118
+ return /* @__PURE__ */ React.createElement("div", { className: ["flex items-center gap-2 mb-3", className].filter(Boolean).join(" ") }, search && /* @__PURE__ */ React.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React.createElement(
119
+ Search,
120
+ {
121
+ size: "md",
122
+ value: search.value,
123
+ onChange: (e) => search.onChange(e.target.value),
124
+ onClear: () => search.onChange(""),
125
+ placeholder: (_a = search.placeholder) != null ? _a : "Buscar..."
126
+ }
127
+ )), pillFilters.length > 0 && /* @__PURE__ */ React.createElement("div", { "data-pill-filter": true, className: "flex items-center [gap:var(--filter-chip-group-gap)] flex-wrap" }, pillFilters.map((p) => /* @__PURE__ */ React.createElement(
128
+ FilterChip,
129
+ {
130
+ key: p.key,
131
+ label: p.label,
132
+ active: p.active,
133
+ count: p.count,
134
+ onClick: p.onClick
135
+ }
136
+ ))), filters.length > 0 && !collapseDesktop && /* @__PURE__ */ React.createElement("div", { className: "hidden md:flex items-center gap-1.5" }, (search || pillFilters.length > 0) && /* @__PURE__ */ React.createElement(Divider, { orientation: "vertical", className: "mx-0.5" }), /* @__PURE__ */ React.createElement(ListFilter, { size: 14, className: "text-fg-disabled shrink-0" }), filters.map((f) => /* @__PURE__ */ React.createElement(FilterDropdown, { key: f.key, f }))), collapseDesktop && /* @__PURE__ */ React.createElement("div", { className: "hidden md:flex items-center gap-1.5" }, (search || pillFilters.length > 0) && /* @__PURE__ */ React.createElement(Divider, { orientation: "vertical", className: "mx-0.5" }), activeFilters.map((f) => /* @__PURE__ */ React.createElement(
137
+ "button",
138
+ {
139
+ key: f.key,
140
+ type: "button",
141
+ onClick: () => f.onChange(""),
142
+ title: f.label,
143
+ className: triggerCls(true)
144
+ },
145
+ getOptionLabel(f),
146
+ /* @__PURE__ */ React.createElement(X, { size: 12 })
147
+ )), /* @__PURE__ */ React.createElement(Popover, { placement: "bottom-end", trigger: /* @__PURE__ */ React.createElement(FiltersButton, { count: activeFilterCount }) }, ({ close }) => /* @__PURE__ */ React.createElement("div", { className: "bg-surface-default border border-stroke-default rounded-(--radius-card) shadow-lg p-4 w-56 max-h-[70vh] overflow-y-auto" }, /* @__PURE__ */ React.createElement(
148
+ FilterGroups,
149
+ {
150
+ filters,
151
+ onPick: (f, v) => {
152
+ f.onChange(v);
153
+ close();
154
+ },
155
+ onClear: onClear ? () => {
156
+ onClear();
157
+ close();
158
+ } : void 0,
159
+ showClear: activeFilterCount > 0
160
+ }
161
+ )))), onClear && activeFilterCount > 0 && !collapseDesktop && /* @__PURE__ */ React.createElement(
162
+ IconButton,
163
+ {
164
+ icon: /* @__PURE__ */ React.createElement(X, { size: 13 }),
165
+ "aria-label": "Limpar filtros",
166
+ size: "sm",
167
+ variant: "ghost",
168
+ color: "neutral",
169
+ className: "hidden md:inline-flex",
170
+ onClick: onClear
171
+ }
172
+ ), singleFilter && !(mobileCollapse && actions) && /* @__PURE__ */ React.createElement("div", { className: "md:hidden" }, /* @__PURE__ */ React.createElement(MobileSingleFilter, { f: singleFilter })), !mobileCollapse && filters.length >= 2 && /* @__PURE__ */ React.createElement("div", { className: "md:hidden" }, /* @__PURE__ */ React.createElement(Popover, { placement: "bottom-end", trigger: /* @__PURE__ */ React.createElement(FiltersButton, { count: activeFilterCount }) }, ({ close }) => /* @__PURE__ */ React.createElement("div", { className: "bg-surface-default border border-stroke-default rounded-(--radius-card) shadow-lg p-4 w-52" }, /* @__PURE__ */ React.createElement(
173
+ FilterGroups,
174
+ {
175
+ filters,
176
+ onPick: (f, v) => {
177
+ f.onChange(v);
178
+ close();
179
+ },
180
+ onClear: onClear ? () => {
181
+ onClear();
182
+ close();
183
+ } : void 0,
184
+ showClear: activeFilterCount > 0
185
+ }
186
+ )))), mobileCollapse && (filters.length >= 2 || actions) && /* @__PURE__ */ React.createElement("div", { className: "md:hidden" }, /* @__PURE__ */ React.createElement(FiltersButton, { count: activeFilterCount, onClick: () => setSheetOpen(true) }), /* @__PURE__ */ React.createElement(BottomSheet, { open: sheetOpen, onClose: () => setSheetOpen(false), title: "Filtros" }, /* @__PURE__ */ React.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React.createElement(
187
+ FilterGroups,
188
+ {
189
+ filters,
190
+ onPick: (f, v) => {
191
+ f.onChange(v);
192
+ setSheetOpen(false);
193
+ },
194
+ onClear: onClear ? () => {
195
+ onClear();
196
+ setSheetOpen(false);
197
+ } : void 0,
198
+ showClear: activeFilterCount > 0
199
+ }
200
+ ), actions && /* @__PURE__ */ React.createElement("div", { className: "pt-2 border-t border-stroke-default" }, actions)))), mobileCollapse ? /* @__PURE__ */ React.createElement("div", { className: "hidden md:flex items-center" }, actions) : actions);
201
+ }
202
+ export {
203
+ DataTableHeader,
204
+ FilterDropdown
205
+ };
@@ -0,0 +1,40 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * DatePicker — input de data com calendar popover.
6
+ *
7
+ * Uso:
8
+ * <DatePicker value={date} onChange={setDate} />
9
+ * <DatePicker value={date} onChange={setDate} min={new Date()} />
10
+ * <DatePicker value={date} onChange={setDate} placeholder="Selecione" />
11
+ *
12
+ * Sem dependências externas — calendar próprio (mês/ano nav, semana ISO).
13
+ * Locale pt-BR por default (segunda como primeiro dia).
14
+ *
15
+ * Limitações conscientes (MVP):
16
+ * - Single date só (sem range)
17
+ */
18
+ interface DatePickerProps {
19
+ /** Label renderada acima do controle (mesmo padrão do Input do DS). */
20
+ label?: ReactNode;
21
+ value: Date | null;
22
+ onChange: (date: Date | null) => void;
23
+ min?: Date;
24
+ max?: Date;
25
+ placeholder?: string;
26
+ size?: 'sm' | 'md';
27
+ width?: 'full' | 'hug';
28
+ /** locale pra formato. default = 'pt-BR'. */
29
+ locale?: string;
30
+ /** Primeiro dia da semana. default = 1 (segunda). */
31
+ weekStartsOn?: 0 | 1;
32
+ disabled?: boolean;
33
+ /** Texto label dos dias da semana (S T Q ...). default = pt-BR. */
34
+ weekdayLabels?: string[];
35
+ className?: string;
36
+ 'aria-label'?: string;
37
+ }
38
+ declare const DatePicker: react.ForwardRefExoticComponent<DatePickerProps & react.RefAttributes<HTMLButtonElement>>;
39
+
40
+ export { DatePicker, type DatePickerProps };
@@ -0,0 +1,252 @@
1
+ "use client";
2
+ import "../chunk-ORMEWXMH.js";
3
+ import { forwardRef, useState, useRef, useEffect, useId, useImperativeHandle } from "react";
4
+ import { Calendar, ChevronLeft, ChevronRight, X } from "lucide-react";
5
+ import { Popover } from "./popover.js";
6
+ const PT_WEEKDAYS_MON_FIRST = ["S", "T", "Q", "Q", "S", "S", "D"];
7
+ const PT_MONTHS = [
8
+ "Janeiro",
9
+ "Fevereiro",
10
+ "Mar\xE7o",
11
+ "Abril",
12
+ "Maio",
13
+ "Junho",
14
+ "Julho",
15
+ "Agosto",
16
+ "Setembro",
17
+ "Outubro",
18
+ "Novembro",
19
+ "Dezembro"
20
+ ];
21
+ const SIZE_CLASS = {
22
+ sm: "h-8 text-caption px-2.5",
23
+ md: "h-10 text-label px-3"
24
+ };
25
+ function startOfDay(d) {
26
+ const x = new Date(d);
27
+ x.setHours(0, 0, 0, 0);
28
+ return x;
29
+ }
30
+ function isSameDay(a, b) {
31
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
32
+ }
33
+ function addDays(d, n) {
34
+ const r = new Date(d);
35
+ r.setDate(r.getDate() + n);
36
+ return r;
37
+ }
38
+ function buildMonthGrid(year, month, weekStartsOn) {
39
+ const first = new Date(year, month, 1);
40
+ const firstWeekday = first.getDay();
41
+ const offset = (firstWeekday - weekStartsOn + 7) % 7;
42
+ const start = new Date(year, month, 1 - offset);
43
+ const days = [];
44
+ for (let i = 0; i < 42; i++) {
45
+ days.push(new Date(start.getFullYear(), start.getMonth(), start.getDate() + i));
46
+ }
47
+ return days;
48
+ }
49
+ const DatePicker = forwardRef(function DatePicker2({
50
+ label,
51
+ value,
52
+ onChange,
53
+ min,
54
+ max,
55
+ placeholder = "Selecione\u2026",
56
+ size = "md",
57
+ width = "full",
58
+ locale = "pt-BR",
59
+ weekStartsOn = 1,
60
+ disabled = false,
61
+ weekdayLabels,
62
+ className = "",
63
+ "aria-label": ariaLabel
64
+ }, ref) {
65
+ const triggerId = useId();
66
+ const [open, setOpen] = useState(false);
67
+ const [view, setView] = useState(() => {
68
+ const r = value != null ? value : /* @__PURE__ */ new Date();
69
+ return { year: r.getFullYear(), month: r.getMonth() };
70
+ });
71
+ const [focusedDate, setFocusedDate] = useState(null);
72
+ const triggerRef = useRef(null);
73
+ const activeDayRef = useRef(null);
74
+ useImperativeHandle(ref, () => triggerRef.current);
75
+ useEffect(() => {
76
+ if (open && value) {
77
+ setView({ year: value.getFullYear(), month: value.getMonth() });
78
+ }
79
+ }, [open, value]);
80
+ useEffect(() => {
81
+ if (!open) setFocusedDate(null);
82
+ }, [open]);
83
+ useEffect(() => {
84
+ var _a;
85
+ if (focusedDate) (_a = activeDayRef.current) == null ? void 0 : _a.focus();
86
+ }, [focusedDate]);
87
+ function isDisabled(date) {
88
+ if (min && startOfDay(date) < startOfDay(min)) return true;
89
+ if (max && startOfDay(date) > startOfDay(max)) return true;
90
+ return false;
91
+ }
92
+ function handleSelect(date) {
93
+ if (isDisabled(date)) return;
94
+ onChange(date);
95
+ setOpen(false);
96
+ }
97
+ function handleClear(e) {
98
+ var _a;
99
+ e.stopPropagation();
100
+ onChange(null);
101
+ (_a = triggerRef.current) == null ? void 0 : _a.focus();
102
+ }
103
+ function handleGridKeyDown(e) {
104
+ var _a;
105
+ const base = (_a = focusedDate != null ? focusedDate : value) != null ? _a : new Date(view.year, view.month, 1);
106
+ let next = null;
107
+ if (e.key === "ArrowRight") {
108
+ e.preventDefault();
109
+ next = addDays(base, 1);
110
+ } else if (e.key === "ArrowLeft") {
111
+ e.preventDefault();
112
+ next = addDays(base, -1);
113
+ } else if (e.key === "ArrowDown") {
114
+ e.preventDefault();
115
+ next = addDays(base, 7);
116
+ } else if (e.key === "ArrowUp") {
117
+ e.preventDefault();
118
+ next = addDays(base, -7);
119
+ } else if (e.key === "Enter" && focusedDate && !isDisabled(focusedDate)) {
120
+ e.preventDefault();
121
+ handleSelect(focusedDate);
122
+ return;
123
+ }
124
+ if (next) {
125
+ setFocusedDate(next);
126
+ if (next.getMonth() !== view.month || next.getFullYear() !== view.year) {
127
+ setView({ year: next.getFullYear(), month: next.getMonth() });
128
+ }
129
+ }
130
+ }
131
+ function nav(delta) {
132
+ setView(({ year, month }) => {
133
+ const m = month + delta;
134
+ if (m < 0) return { year: year - 1, month: 11 };
135
+ if (m > 11) return { year: year + 1, month: 0 };
136
+ return { year, month: m };
137
+ });
138
+ }
139
+ const tabFocusDate = focusedDate != null ? focusedDate : value;
140
+ const days = buildMonthGrid(view.year, view.month, weekStartsOn);
141
+ const weekdays = weekdayLabels != null ? weekdayLabels : weekStartsOn === 1 ? PT_WEEKDAYS_MON_FIRST : ["D", ...PT_WEEKDAYS_MON_FIRST.slice(0, 6)];
142
+ const today = startOfDay(/* @__PURE__ */ new Date());
143
+ const formatted = value ? value.toLocaleDateString(locale, { day: "2-digit", month: "2-digit", year: "numeric" }) : "";
144
+ const calendar = /* @__PURE__ */ React.createElement(
145
+ "div",
146
+ {
147
+ role: "dialog",
148
+ "aria-label": "Calend\xE1rio",
149
+ className: "rounded-(--radius-control) border border-stroke-control bg-surface-default shadow-lg p-3 w-[280px]"
150
+ },
151
+ /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between mb-3" }, /* @__PURE__ */ React.createElement(
152
+ "button",
153
+ {
154
+ type: "button",
155
+ onClick: () => nav(-1),
156
+ "aria-label": "M\xEAs anterior",
157
+ className: "p-1 rounded hover:bg-surface-raised text-fg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-stroke-focus"
158
+ },
159
+ /* @__PURE__ */ React.createElement(ChevronLeft, { size: 16 })
160
+ ), /* @__PURE__ */ React.createElement("span", { className: "text-label font-semibold text-fg-primary" }, PT_MONTHS[view.month], " ", view.year), /* @__PURE__ */ React.createElement(
161
+ "button",
162
+ {
163
+ type: "button",
164
+ onClick: () => nav(1),
165
+ "aria-label": "Pr\xF3ximo m\xEAs",
166
+ className: "p-1 rounded hover:bg-surface-raised text-fg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-stroke-focus"
167
+ },
168
+ /* @__PURE__ */ React.createElement(ChevronRight, { size: 16 })
169
+ )),
170
+ /* @__PURE__ */ React.createElement("div", { className: "grid grid-cols-7 gap-1 mb-1" }, weekdays.map((w, i) => /* @__PURE__ */ React.createElement("div", { key: i, className: "text-center text-[10px] font-semibold text-fg-muted uppercase" }, w))),
171
+ /* @__PURE__ */ React.createElement("div", { role: "grid", className: "grid grid-cols-7 gap-1", onKeyDown: handleGridKeyDown }, days.map((d, i) => {
172
+ const inMonth = d.getMonth() === view.month;
173
+ const isToday = isSameDay(d, today);
174
+ const isSelected = !!value && isSameDay(d, value);
175
+ const isFocused = !!tabFocusDate && isSameDay(d, tabFocusDate);
176
+ const dis = isDisabled(d);
177
+ return /* @__PURE__ */ React.createElement(
178
+ "button",
179
+ {
180
+ key: i,
181
+ ref: isFocused ? activeDayRef : void 0,
182
+ type: "button",
183
+ role: "gridcell",
184
+ onClick: () => handleSelect(d),
185
+ disabled: dis,
186
+ "aria-selected": isSelected,
187
+ "aria-label": d.toLocaleDateString(locale, { weekday: "long", day: "numeric", month: "long", year: "numeric" }),
188
+ tabIndex: isFocused ? 0 : -1,
189
+ className: [
190
+ "h-8 rounded text-caption font-medium transition-colors",
191
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-stroke-focus",
192
+ "disabled:cursor-not-allowed disabled:opacity-30",
193
+ isSelected ? "bg-brand-primary text-brand-on-primary" : isToday ? "border border-stroke-focus text-fg-primary hover:bg-surface-raised" : inMonth ? "text-fg-primary hover:bg-surface-raised" : "text-fg-disabled hover:bg-surface-raised"
194
+ ].join(" ")
195
+ },
196
+ d.getDate()
197
+ );
198
+ }))
199
+ );
200
+ const control = /* @__PURE__ */ React.createElement("div", { className: ["relative", width === "full" ? "block w-full" : "inline-block", label ? "" : className].join(" ") }, /* @__PURE__ */ React.createElement(
201
+ Popover,
202
+ {
203
+ trigger: /* @__PURE__ */ React.createElement(
204
+ "button",
205
+ {
206
+ ref: triggerRef,
207
+ id: triggerId,
208
+ type: "button",
209
+ onClick: (e) => {
210
+ e.stopPropagation();
211
+ if (!disabled) setOpen((o) => !o);
212
+ },
213
+ disabled,
214
+ "aria-label": ariaLabel != null ? ariaLabel : "Selecionar data",
215
+ "aria-haspopup": "dialog",
216
+ "aria-expanded": open,
217
+ className: [
218
+ "w-full flex items-center gap-2 rounded-(--radius-control) border border-stroke-control bg-surface-default",
219
+ "transition-colors focus:outline-none focus:border-stroke-focus focus:ring-2 focus:ring-stroke-focus/20",
220
+ "disabled:opacity-50 disabled:cursor-not-allowed",
221
+ value ? "pr-7" : "",
222
+ SIZE_CLASS[size]
223
+ ].join(" ")
224
+ },
225
+ /* @__PURE__ */ React.createElement(Calendar, { size: 16, className: "text-fg-muted shrink-0" }),
226
+ /* @__PURE__ */ React.createElement("span", { className: ["flex-1 text-left truncate", value ? "text-fg-primary" : "text-fg-placeholder"].join(" ") }, formatted || placeholder)
227
+ ),
228
+ triggerClassName: width === "full" ? "block w-full" : "inline-block",
229
+ placement: "bottom-start",
230
+ offset: 4,
231
+ open,
232
+ onOpenChange: (v) => {
233
+ if (!disabled) setOpen(v);
234
+ }
235
+ },
236
+ () => calendar
237
+ ), value && !disabled && /* @__PURE__ */ React.createElement(
238
+ "button",
239
+ {
240
+ type: "button",
241
+ onClick: handleClear,
242
+ "aria-label": "Limpar data",
243
+ className: "absolute right-2 top-1/2 -translate-y-1/2 text-fg-muted hover:text-fg-primary p-0.5 rounded transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-stroke-focus"
244
+ },
245
+ /* @__PURE__ */ React.createElement(X, { size: 14 })
246
+ ));
247
+ if (!label) return control;
248
+ return /* @__PURE__ */ React.createElement("div", { className: ["flex flex-col gap-1.5", width === "full" ? "w-full" : "inline-flex", className].join(" ") }, /* @__PURE__ */ React.createElement("label", { htmlFor: triggerId, className: "text-label font-medium text-fg-primary" }, label), control);
249
+ });
250
+ export {
251
+ DatePicker
252
+ };
@@ -0,0 +1,20 @@
1
+ import * as react from 'react';
2
+
3
+ /**
4
+ * Divider — separador visual horizontal ou vertical.
5
+ *
6
+ * Uso:
7
+ * <Divider /> // horizontal subtle
8
+ * <Divider orientation="vertical" /> // vertical
9
+ * <Divider variant="strong" /> // mais visível
10
+ * <Divider><span>OU</span></Divider> // com label centralizado
11
+ */
12
+ interface DividerProps {
13
+ orientation?: 'horizontal' | 'vertical';
14
+ variant?: 'subtle' | 'default' | 'strong';
15
+ className?: string;
16
+ children?: React.ReactNode;
17
+ }
18
+ declare function Divider({ orientation, variant, className, children, }: DividerProps): react.JSX.Element;
19
+
20
+ export { Divider, type DividerProps };
@@ -0,0 +1,47 @@
1
+ import "../chunk-ORMEWXMH.js";
2
+ const COLOR_BY_VARIANT = {
3
+ subtle: "bg-stroke-subtle",
4
+ default: "bg-stroke-default",
5
+ strong: "bg-stroke-strong"
6
+ };
7
+ function Divider({
8
+ orientation = "horizontal",
9
+ variant = "default",
10
+ className = "",
11
+ children
12
+ }) {
13
+ if (orientation === "vertical") {
14
+ return /* @__PURE__ */ React.createElement(
15
+ "div",
16
+ {
17
+ role: "separator",
18
+ "aria-orientation": "vertical",
19
+ className: ["shrink-0 self-stretch w-px", COLOR_BY_VARIANT[variant], className].join(" ")
20
+ }
21
+ );
22
+ }
23
+ if (children) {
24
+ return /* @__PURE__ */ React.createElement(
25
+ "div",
26
+ {
27
+ role: "separator",
28
+ "aria-orientation": "horizontal",
29
+ className: ["flex items-center gap-3 my-2", className].join(" ")
30
+ },
31
+ /* @__PURE__ */ React.createElement("span", { className: ["flex-1 h-px", COLOR_BY_VARIANT[variant]].join(" ") }),
32
+ /* @__PURE__ */ React.createElement("span", { className: "text-caption text-fg-muted shrink-0" }, children),
33
+ /* @__PURE__ */ React.createElement("span", { className: ["flex-1 h-px", COLOR_BY_VARIANT[variant]].join(" ") })
34
+ );
35
+ }
36
+ return /* @__PURE__ */ React.createElement(
37
+ "hr",
38
+ {
39
+ role: "separator",
40
+ "aria-orientation": "horizontal",
41
+ className: ["border-0 h-px my-2", COLOR_BY_VARIANT[variant], className].join(" ")
42
+ }
43
+ );
44
+ }
45
+ export {
46
+ Divider
47
+ };
@@ -0,0 +1,26 @@
1
+ import * as react from 'react';
2
+
3
+ type DrawerSize = 'sm' | 'md' | 'lg' | 'xl';
4
+ interface DrawerProps {
5
+ open: boolean;
6
+ onClose: () => void;
7
+ title?: React.ReactNode;
8
+ /** Subtítulo opcional abaixo do title. */
9
+ subtitle?: React.ReactNode;
10
+ children: React.ReactNode;
11
+ footer?: React.ReactNode;
12
+ side?: 'left' | 'right';
13
+ /** Tamanho preset. Sobrescreve `width` se ambos passados. */
14
+ size?: DrawerSize;
15
+ /** Largura custom (Tailwind class, ex: "w-96"). Use só se size não atende. */
16
+ width?: string;
17
+ closeOnBackdrop?: boolean;
18
+ hideClose?: boolean;
19
+ className?: string;
20
+ /** Alvo do portal. default = document.body. Passe um elemento de um subtree TEMATIZADO (ex.: a
21
+ * raiz do tema da loja) pra o drawer herdar tokens/mode/fonte daquele contexto em vez do global. */
22
+ container?: Element | null;
23
+ }
24
+ declare function Drawer({ open, onClose, title, subtitle, children, footer, side, size, width, closeOnBackdrop, hideClose, className, container, }: DrawerProps): react.ReactPortal | null;
25
+
26
+ export { Drawer, type DrawerProps, type DrawerSize };
@@ -0,0 +1,82 @@
1
+ "use client";
2
+ import "../chunk-ORMEWXMH.js";
3
+ import { useEffect, useId } from "react";
4
+ import { X } from "lucide-react";
5
+ import { createPortal } from "react-dom";
6
+ import { useFocusTrap } from "./use-focus-trap.js";
7
+ const SIZE_WIDTH = {
8
+ sm: "w-80",
9
+ // 320px
10
+ md: "w-96",
11
+ // 384px
12
+ lg: "w-[480px]",
13
+ xl: "w-[640px]"
14
+ };
15
+ function Drawer({
16
+ open,
17
+ onClose,
18
+ title,
19
+ subtitle,
20
+ children,
21
+ footer,
22
+ side = "right",
23
+ size,
24
+ width,
25
+ closeOnBackdrop = true,
26
+ hideClose = false,
27
+ className = "",
28
+ container
29
+ }) {
30
+ const widthClass = width != null ? width : SIZE_WIDTH[size != null ? size : "md"];
31
+ const titleId = useId();
32
+ const panelRef = useFocusTrap(open);
33
+ useEffect(() => {
34
+ if (!open) return;
35
+ const prev = document.body.style.overflow;
36
+ document.body.style.overflow = "hidden";
37
+ const onKey = (e) => {
38
+ if (e.key === "Escape") onClose();
39
+ };
40
+ document.addEventListener("keydown", onKey);
41
+ return () => {
42
+ document.body.style.overflow = prev;
43
+ document.removeEventListener("keydown", onKey);
44
+ };
45
+ }, [open, onClose]);
46
+ if (!open) return null;
47
+ return createPortal(
48
+ /* @__PURE__ */ React.createElement("div", { className: "fixed inset-0 z-50 flex" }, /* @__PURE__ */ React.createElement("div", { className: "absolute inset-0 [background:var(--overlay-scrim)]", onClick: closeOnBackdrop ? onClose : void 0, "aria-hidden": "true" }), /* @__PURE__ */ React.createElement(
49
+ "div",
50
+ {
51
+ ref: panelRef,
52
+ role: "dialog",
53
+ "aria-modal": "true",
54
+ "aria-labelledby": title ? titleId : void 0,
55
+ tabIndex: -1,
56
+ className: [
57
+ "relative z-10 flex flex-col bg-surface-default shadow-xl h-full max-w-full",
58
+ "focus:outline-none",
59
+ widthClass,
60
+ side === "right" ? "ml-auto" : "mr-auto",
61
+ className
62
+ ].join(" ")
63
+ },
64
+ (title || !hideClose) && /* @__PURE__ */ React.createElement("div", { className: "flex items-start justify-between gap-4 px-6 py-4 border-b border-stroke-default shrink-0" }, /* @__PURE__ */ React.createElement("div", { className: "flex-1 min-w-0" }, title && /* @__PURE__ */ React.createElement("h2", { id: titleId, className: "text-body font-semibold text-fg-primary" }, title), subtitle && /* @__PURE__ */ React.createElement("p", { className: "text-label text-fg-muted mt-0.5" }, subtitle)), !hideClose && /* @__PURE__ */ React.createElement(
65
+ "button",
66
+ {
67
+ type: "button",
68
+ onClick: onClose,
69
+ className: "shrink-0 text-fg-muted hover:text-fg-primary transition-colors rounded focus-visible:ring-2 focus-visible:ring-stroke-focus focus-visible:outline-none p-0.5",
70
+ "aria-label": "Fechar"
71
+ },
72
+ /* @__PURE__ */ React.createElement(X, { size: 20 })
73
+ )),
74
+ /* @__PURE__ */ React.createElement("div", { className: "flex-1 overflow-y-auto px-6 py-4" }, children),
75
+ footer && /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-end gap-3 px-6 py-4 border-t border-stroke-default shrink-0" }, footer)
76
+ )),
77
+ container != null ? container : document.body
78
+ );
79
+ }
80
+ export {
81
+ Drawer
82
+ };