@rendra-ui/web 2.1.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 (150) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +433 -0
  3. package/bin/rendra.mjs +114 -0
  4. package/dist/base.css +246 -0
  5. package/dist/button-DIcpJwK9.js +143 -0
  6. package/dist/button-DIcpJwK9.js.map +1 -0
  7. package/dist/chart.js +520 -0
  8. package/dist/chart.js.map +1 -0
  9. package/dist/cli/auditar.js +125 -0
  10. package/dist/cli/auditar.js.map +1 -0
  11. package/dist/cli/codigos.js +15 -0
  12. package/dist/cli/codigos.js.map +1 -0
  13. package/dist/cli/help.js +17 -0
  14. package/dist/cli/help.js.map +1 -0
  15. package/dist/cli/trocar.js +242 -0
  16. package/dist/cli/trocar.js.map +1 -0
  17. package/dist/cli/typescript-loader.js +27 -0
  18. package/dist/cli/typescript-loader.js.map +1 -0
  19. package/dist/cn-DVPheE99.js +22 -0
  20. package/dist/cn-DVPheE99.js.map +1 -0
  21. package/dist/components-Cm2ezlPT.js +800 -0
  22. package/dist/components-Cm2ezlPT.js.map +1 -0
  23. package/dist/components.css +3365 -0
  24. package/dist/document-viewer.js +204 -0
  25. package/dist/document-viewer.js.map +1 -0
  26. package/dist/empty-state-DtyZAfYb.js +168 -0
  27. package/dist/empty-state-DtyZAfYb.js.map +1 -0
  28. package/dist/index.js +10530 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/rendra-provider-cCnquOZy.js +88 -0
  31. package/dist/rendra-provider-cCnquOZy.js.map +1 -0
  32. package/dist/rich-text-editor.js +439 -0
  33. package/dist/rich-text-editor.js.map +1 -0
  34. package/dist/router-bridge.js +51 -0
  35. package/dist/router-bridge.js.map +1 -0
  36. package/dist/tokens.css +732 -0
  37. package/dist/tooltip-DyeuGPCc.js +105 -0
  38. package/dist/tooltip-DyeuGPCc.js.map +1 -0
  39. package/dist/types/brand/apply-theme.d.ts +9 -0
  40. package/dist/types/brand/brand-context.d.ts +21 -0
  41. package/dist/types/brand/brand-provider.d.ts +49 -0
  42. package/dist/types/brand/palette.d.ts +63 -0
  43. package/dist/types/brand/public.d.ts +6 -0
  44. package/dist/types/brand/theme.d.ts +80 -0
  45. package/dist/types/brand/types.d.ts +54 -0
  46. package/dist/types/brand/use-brand.d.ts +1 -0
  47. package/dist/types/catalog/components.d.ts +81 -0
  48. package/dist/types/chart.d.ts +1 -0
  49. package/dist/types/components/app-shell/app-shell.d.ts +36 -0
  50. package/dist/types/components/app-shell/command-search.d.ts +1 -0
  51. package/dist/types/components/app-shell/header.d.ts +1 -0
  52. package/dist/types/components/app-shell/layout.d.ts +53 -0
  53. package/dist/types/components/app-shell/mega-menu.d.ts +1 -0
  54. package/dist/types/components/app-shell/navigation-utils.d.ts +18 -0
  55. package/dist/types/components/app-shell/notifications.d.ts +6 -0
  56. package/dist/types/components/app-shell/shell-context.d.ts +48 -0
  57. package/dist/types/components/app-shell/sidebar.d.ts +1 -0
  58. package/dist/types/components/app-shell/types.d.ts +53 -0
  59. package/dist/types/components/layout/index.d.ts +4 -0
  60. package/dist/types/components/layout/page-header.d.ts +38 -0
  61. package/dist/types/components/layout/primitives.d.ts +71 -0
  62. package/dist/types/components/layout/tokens.d.ts +43 -0
  63. package/dist/types/components/rendra-provider.d.ts +48 -0
  64. package/dist/types/components/rendra-router-bridge.d.ts +18 -0
  65. package/dist/types/components/ui/accordion.d.ts +16 -0
  66. package/dist/types/components/ui/action-bar.d.ts +35 -0
  67. package/dist/types/components/ui/alert.d.ts +26 -0
  68. package/dist/types/components/ui/avatar.d.ts +23 -0
  69. package/dist/types/components/ui/badge.d.ts +15 -0
  70. package/dist/types/components/ui/brand-feedback-icon.d.ts +26 -0
  71. package/dist/types/components/ui/brand-logo.d.ts +8 -0
  72. package/dist/types/components/ui/breadcrumb.d.ts +19 -0
  73. package/dist/types/components/ui/button-group.d.ts +27 -0
  74. package/dist/types/components/ui/button.d.ts +30 -0
  75. package/dist/types/components/ui/calendar.d.ts +34 -0
  76. package/dist/types/components/ui/card.d.ts +32 -0
  77. package/dist/types/components/ui/chart.d.ts +57 -0
  78. package/dist/types/components/ui/chat.d.ts +137 -0
  79. package/dist/types/components/ui/checkbox.d.ts +37 -0
  80. package/dist/types/components/ui/checklist.d.ts +16 -0
  81. package/dist/types/components/ui/color-picker.d.ts +13 -0
  82. package/dist/types/components/ui/data-toolbar.d.ts +37 -0
  83. package/dist/types/components/ui/date-picker.d.ts +41 -0
  84. package/dist/types/components/ui/document-viewer.d.ts +19 -0
  85. package/dist/types/components/ui/drawer.d.ts +30 -0
  86. package/dist/types/components/ui/dropdown-menu.d.ts +20 -0
  87. package/dist/types/components/ui/empty-state.d.ts +15 -0
  88. package/dist/types/components/ui/error-page.d.ts +13 -0
  89. package/dist/types/components/ui/field.d.ts +42 -0
  90. package/dist/types/components/ui/form.d.ts +42 -0
  91. package/dist/types/components/ui/image-cropper.d.ts +55 -0
  92. package/dist/types/components/ui/image-viewer.d.ts +14 -0
  93. package/dist/types/components/ui/info-hint.d.ts +9 -0
  94. package/dist/types/components/ui/input.d.ts +91 -0
  95. package/dist/types/components/ui/kanban.d.ts +98 -0
  96. package/dist/types/components/ui/list.d.ts +31 -0
  97. package/dist/types/components/ui/modal.d.ts +27 -0
  98. package/dist/types/components/ui/otp-input.d.ts +17 -0
  99. package/dist/types/components/ui/overlay-shell.d.ts +14 -0
  100. package/dist/types/components/ui/pagination.d.ts +18 -0
  101. package/dist/types/components/ui/picker-panel.d.ts +24 -0
  102. package/dist/types/components/ui/popover.d.ts +12 -0
  103. package/dist/types/components/ui/progress.d.ts +16 -0
  104. package/dist/types/components/ui/qr-code.d.ts +13 -0
  105. package/dist/types/components/ui/radio-group.d.ts +27 -0
  106. package/dist/types/components/ui/rating.d.ts +19 -0
  107. package/dist/types/components/ui/rendra-credit.d.ts +12 -0
  108. package/dist/types/components/ui/repeatable-field.d.ts +22 -0
  109. package/dist/types/components/ui/rich-text-editor.d.ts +21 -0
  110. package/dist/types/components/ui/select.d.ts +65 -0
  111. package/dist/types/components/ui/separator.d.ts +7 -0
  112. package/dist/types/components/ui/skeleton.d.ts +3 -0
  113. package/dist/types/components/ui/slider.d.ts +18 -0
  114. package/dist/types/components/ui/sortable-handle.d.ts +16 -0
  115. package/dist/types/components/ui/spinner.d.ts +7 -0
  116. package/dist/types/components/ui/stat-card.d.ts +20 -0
  117. package/dist/types/components/ui/switch.d.ts +15 -0
  118. package/dist/types/components/ui/table.d.ts +134 -0
  119. package/dist/types/components/ui/tabs.d.ts +25 -0
  120. package/dist/types/components/ui/textarea.d.ts +10 -0
  121. package/dist/types/components/ui/timeline.d.ts +18 -0
  122. package/dist/types/components/ui/toast.d.ts +18 -0
  123. package/dist/types/components/ui/tooltip.d.ts +17 -0
  124. package/dist/types/components/ui/upload.d.ts +50 -0
  125. package/dist/types/components/ui/widget-grid.d.ts +22 -0
  126. package/dist/types/components/ui/wizard.d.ts +38 -0
  127. package/dist/types/document-viewer.d.ts +1 -0
  128. package/dist/types/hooks/use-breakpoint.d.ts +21 -0
  129. package/dist/types/hooks/use-debounced-value.d.ts +5 -0
  130. package/dist/types/hooks/use-fill-height.d.ts +6 -0
  131. package/dist/types/hooks/use-lookup.d.ts +30 -0
  132. package/dist/types/hooks/use-reduced-motion.d.ts +1 -0
  133. package/dist/types/index.d.ts +76 -0
  134. package/dist/types/lib/cn.d.ts +2 -0
  135. package/dist/types/lib/contrast.d.ts +2 -0
  136. package/dist/types/lib/control.d.ts +20 -0
  137. package/dist/types/lib/lookup.d.ts +22 -0
  138. package/dist/types/lib/masks.d.ts +46 -0
  139. package/dist/types/lib/qr-encode.d.ts +48 -0
  140. package/dist/types/lib/shape.d.ts +8 -0
  141. package/dist/types/lib/sortable.d.ts +72 -0
  142. package/dist/types/lib/validators.d.ts +14 -0
  143. package/dist/types/rendra-router-bridge.d.ts +1 -0
  144. package/dist/types/rich-text-editor.d.ts +1 -0
  145. package/dist/types/widget-grid.d.ts +1 -0
  146. package/dist/use-breakpoint-BmXOZtF9.js +49 -0
  147. package/dist/use-breakpoint-BmXOZtF9.js.map +1 -0
  148. package/dist/widget-grid.js +118 -0
  149. package/dist/widget-grid.js.map +1 -0
  150. package/package.json +182 -0
package/dist/base.css ADDED
@@ -0,0 +1,246 @@
1
+ /*! Rendra Design System v2.1.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
+
3
+ @layer base {
4
+ *,
5
+ ::after,
6
+ ::before,
7
+ ::backdrop,
8
+ ::file-selector-button {
9
+ box-sizing: border-box;
10
+ margin: 0;
11
+ padding: 0;
12
+ border: 0 solid;
13
+ }
14
+ html,
15
+ :host {
16
+ line-height: 1.5;
17
+ -webkit-text-size-adjust: 100%;
18
+ tab-size: 4;
19
+ font-family: var(--rendra-brand-font);
20
+ font-feature-settings: var(--default-font-feature-settings, normal);
21
+ font-variation-settings: var(--default-font-variation-settings, normal);
22
+ -webkit-tap-highlight-color: transparent;
23
+ }
24
+ hr {
25
+ height: 0;
26
+ color: inherit;
27
+ border-top-width: 1px;
28
+ }
29
+ abbr:where([title]) {
30
+ -webkit-text-decoration: underline dotted;
31
+ text-decoration: underline dotted;
32
+ }
33
+ h1,
34
+ h2,
35
+ h3,
36
+ h4,
37
+ h5,
38
+ h6 {
39
+ font-size: inherit;
40
+ font-weight: inherit;
41
+ }
42
+ a {
43
+ color: inherit;
44
+ -webkit-text-decoration: inherit;
45
+ text-decoration: inherit;
46
+ }
47
+ b,
48
+ strong {
49
+ font-weight: bolder;
50
+ }
51
+ code,
52
+ kbd,
53
+ samp,
54
+ pre {
55
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
56
+ font-feature-settings: var(--default-mono-font-feature-settings, normal);
57
+ font-variation-settings: var(--default-mono-font-variation-settings, normal);
58
+ font-size: 1em;
59
+ }
60
+ small {
61
+ font-size: 80%;
62
+ }
63
+ sub,
64
+ sup {
65
+ font-size: 75%;
66
+ line-height: 0;
67
+ position: relative;
68
+ vertical-align: baseline;
69
+ }
70
+ sub {
71
+ bottom: -0.25em;
72
+ }
73
+ sup {
74
+ top: -0.5em;
75
+ }
76
+ table {
77
+ text-indent: 0;
78
+ border-color: inherit;
79
+ border-collapse: collapse;
80
+ }
81
+ :-moz-focusring:where(:not(iframe)) {
82
+ outline: auto;
83
+ }
84
+ progress {
85
+ vertical-align: baseline;
86
+ }
87
+ summary {
88
+ display: list-item;
89
+ }
90
+ ol,
91
+ ul,
92
+ menu {
93
+ list-style: none;
94
+ }
95
+ img,
96
+ svg,
97
+ video,
98
+ canvas,
99
+ audio,
100
+ iframe,
101
+ embed,
102
+ object {
103
+ display: block;
104
+ vertical-align: middle;
105
+ }
106
+ img,
107
+ video {
108
+ max-width: 100%;
109
+ height: auto;
110
+ }
111
+ button,
112
+ input,
113
+ select,
114
+ optgroup,
115
+ textarea,
116
+ ::file-selector-button {
117
+ font: inherit;
118
+ font-feature-settings: inherit;
119
+ font-variation-settings: inherit;
120
+ letter-spacing: inherit;
121
+ color: inherit;
122
+ border-radius: 0;
123
+ background-color: transparent;
124
+ opacity: 1;
125
+ }
126
+ :where(select:is([multiple], [size])) optgroup {
127
+ font-weight: bolder;
128
+ }
129
+ :where(select:is([multiple], [size])) optgroup option {
130
+ padding-inline-start: 20px;
131
+ }
132
+ ::file-selector-button {
133
+ margin-inline-end: 4px;
134
+ }
135
+ ::placeholder {
136
+ opacity: 1;
137
+ }
138
+ @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
139
+ ::placeholder {
140
+ color: currentcolor;
141
+ @supports (color: color-mix(in lab, red, red)) {
142
+ color: color-mix(in oklab, currentcolor 50%, transparent);
143
+ }
144
+ }
145
+ }
146
+ textarea {
147
+ resize: vertical;
148
+ }
149
+ ::-webkit-search-decoration {
150
+ -webkit-appearance: none;
151
+ }
152
+ ::-webkit-date-and-time-value {
153
+ min-height: 1lh;
154
+ text-align: inherit;
155
+ }
156
+ ::-webkit-datetime-edit {
157
+ display: inline-flex;
158
+ }
159
+ ::-webkit-datetime-edit-fields-wrapper {
160
+ padding: 0;
161
+ }
162
+ ::-webkit-datetime-edit,
163
+ ::-webkit-datetime-edit-year-field,
164
+ ::-webkit-datetime-edit-month-field,
165
+ ::-webkit-datetime-edit-day-field,
166
+ ::-webkit-datetime-edit-hour-field,
167
+ ::-webkit-datetime-edit-minute-field,
168
+ ::-webkit-datetime-edit-second-field,
169
+ ::-webkit-datetime-edit-millisecond-field,
170
+ ::-webkit-datetime-edit-meridiem-field {
171
+ padding-block: 0;
172
+ }
173
+ ::-webkit-calendar-picker-indicator {
174
+ line-height: 1;
175
+ }
176
+ :-moz-ui-invalid {
177
+ box-shadow: none;
178
+ }
179
+ button,
180
+ input:where([type='button'], [type='reset'], [type='submit']),
181
+ ::file-selector-button {
182
+ appearance: button;
183
+ }
184
+ ::-webkit-inner-spin-button,
185
+ ::-webkit-outer-spin-button {
186
+ height: auto;
187
+ }
188
+ [hidden]:where(:not([hidden='until-found'])) {
189
+ display: none !important;
190
+ }
191
+ }
192
+
193
+ @layer rendra.base {
194
+ html {
195
+ font-family: var(--rendra-brand-font);
196
+ -webkit-text-size-adjust: 100%;
197
+ text-rendering: optimizeLegibility;
198
+ -webkit-tap-highlight-color: transparent;
199
+ }
200
+ body {
201
+ min-height: 100dvh;
202
+ background-color: var(--rendra-background);
203
+ font-size: 1rem;
204
+ line-height: var(--tw-leading, 1.5rem);
205
+ letter-spacing: var(--tw-tracking, 0em);
206
+ color: var(--rendra-foreground);
207
+ -webkit-font-smoothing: antialiased;
208
+ -moz-osx-font-smoothing: grayscale;
209
+ background-image: var(--rendra-background-image);
210
+ background-attachment: fixed;
211
+ }
212
+ *,
213
+ ::before,
214
+ ::after {
215
+ border-color: var(--rendra-border);
216
+ }
217
+ h1,
218
+ h2,
219
+ h3,
220
+ h4 {
221
+ --tw-font-weight: 600;
222
+ font-weight: 600;
223
+ text-wrap: balance;
224
+ }
225
+ p {
226
+ text-wrap: pretty;
227
+ }
228
+ :focus-visible {
229
+ outline: 2px solid var(--rendra-ring);
230
+ outline-offset: 2px;
231
+ }
232
+ ::selection {
233
+ background-color: var(--rendra-primary-soft);
234
+ color: var(--rendra-primary-soft-foreground);
235
+ }
236
+ @media (prefers-reduced-motion: reduce) {
237
+ *,
238
+ ::before,
239
+ ::after {
240
+ animation-duration: 0.01ms !important;
241
+ animation-iteration-count: 1 !important;
242
+ transition-duration: 0.01ms !important;
243
+ scroll-behavior: auto !important;
244
+ }
245
+ }
246
+ }
@@ -0,0 +1,143 @@
1
+ /*! Rendra Design System v2.1.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
+ import { t as cn } from "./cn-DVPheE99.js";
3
+ import { p as resolveCatalogCode } from "./components-Cm2ezlPT.js";
4
+ import { Loader2 } from "lucide-react";
5
+ import { Slot } from "radix-ui";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { forwardRef, useSyncExternalStore } from "react";
8
+ import { cva } from "class-variance-authority";
9
+ //#region src/hooks/use-reduced-motion.ts
10
+ function subscribe(cb) {
11
+ const mq = matchMedia("(prefers-reduced-motion: reduce)");
12
+ mq.addEventListener("change", cb);
13
+ return () => mq.removeEventListener("change", cb);
14
+ }
15
+ function getCurrent() {
16
+ return matchMedia("(prefers-reduced-motion: reduce)").matches;
17
+ }
18
+ function usePrefersReducedMotion() {
19
+ return useSyncExternalStore(subscribe, getCurrent, () => false);
20
+ }
21
+ //#endregion
22
+ //#region src/components/ui/spinner.tsx
23
+ var sizeClass = {
24
+ sm: "size-icon-sm",
25
+ md: "size-icon-md",
26
+ lg: "size-icon-lg"
27
+ };
28
+ function Spinner({ size = "md", label, className }) {
29
+ const reduced = usePrefersReducedMotion();
30
+ const icon = /* @__PURE__ */ jsx(Loader2, {
31
+ "aria-hidden": true,
32
+ className: cn(sizeClass[size], reduced ? "" : "animate-spin")
33
+ });
34
+ if (!label) return /* @__PURE__ */ jsx("span", {
35
+ "data-rendra": "SPIN-001",
36
+ "aria-hidden": true,
37
+ className: cn("inline-flex", className),
38
+ children: icon
39
+ });
40
+ return /* @__PURE__ */ jsxs("span", {
41
+ "data-rendra": "SPIN-001",
42
+ role: "status",
43
+ className: cn("inline-flex items-center gap-2", className),
44
+ children: [icon, /* @__PURE__ */ jsx("span", {
45
+ className: "sr-only",
46
+ children: label
47
+ })]
48
+ });
49
+ }
50
+ //#endregion
51
+ //#region src/components/ui/button.tsx
52
+ /**
53
+ * Botão único do sistema. Variantes, tamanho, ícone, só ícone, carregamento e
54
+ * largura total são props: nunca crie outro arquivo de botão.
55
+ * Altura vem de h-control-*: 44px ou mais no mobile, compacta a partir de md.
56
+ */
57
+ var buttonVariants = cva("inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 rounded-control font-medium whitespace-nowrap transition-[color,background-color,border-color,box-shadow,transform] duration-150 ease-out select-none active:scale-98 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 motion-reduce:active:scale-100 [&_svg]:pointer-events-none [&_svg]:shrink-0", {
58
+ variants: {
59
+ variant: {
60
+ primary: "bg-primary text-primary-foreground shadow-sm hover:bg-primary-hover hover:text-primary-hover-foreground hover:shadow-md active:bg-primary-hover active:text-primary-hover-foreground active:shadow-sm",
61
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary-hover hover:text-secondary-hover-foreground hover:shadow-md active:bg-secondary-hover active:text-secondary-hover-foreground active:shadow-sm",
62
+ outline: "border border-input bg-card text-foreground hover:border-primary hover:bg-primary-soft hover:text-primary-soft-foreground active:bg-primary-soft",
63
+ ghost: "text-foreground hover:bg-primary-soft hover:text-primary-soft-foreground active:bg-primary-soft",
64
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive-hover hover:shadow-md active:bg-destructive-hover active:shadow-sm",
65
+ link: "min-h-touch min-w-touch text-primary-text underline-offset-4 hover:text-primary-hover hover:underline md:min-h-0 md:min-w-0"
66
+ },
67
+ size: {
68
+ sm: "h-control-sm px-3 text-sm [&_svg]:size-icon-sm",
69
+ md: "h-control-md px-4 text-sm [&_svg]:size-icon-sm",
70
+ lg: "h-control-lg px-6 text-base [&_svg]:size-icon-md"
71
+ },
72
+ iconOnly: {
73
+ true: "px-0",
74
+ false: ""
75
+ },
76
+ fullWidth: {
77
+ true: "w-full",
78
+ false: ""
79
+ }
80
+ },
81
+ compoundVariants: [
82
+ {
83
+ iconOnly: true,
84
+ size: "sm",
85
+ className: "w-control-sm"
86
+ },
87
+ {
88
+ iconOnly: true,
89
+ size: "md",
90
+ className: "w-control-md"
91
+ },
92
+ {
93
+ iconOnly: true,
94
+ size: "lg",
95
+ className: "w-control-lg"
96
+ },
97
+ {
98
+ variant: "link",
99
+ className: "h-auto px-0"
100
+ }
101
+ ],
102
+ defaultVariants: {
103
+ variant: "primary",
104
+ size: "md",
105
+ iconOnly: false,
106
+ fullWidth: false
107
+ }
108
+ });
109
+ var Button = forwardRef(function Button({ className, variant, size, icon, iconRight, iconOnly = false, loading = false, fullWidth = false, asChild = false, disabled, type = "button", children, ...props }, ref) {
110
+ const classes = cn(buttonVariants({
111
+ variant,
112
+ size,
113
+ iconOnly,
114
+ fullWidth
115
+ }), className);
116
+ const code = resolveCatalogCode("Button", { variant: variant ?? "primary" });
117
+ if (asChild) return /* @__PURE__ */ jsx(Slot.Root, {
118
+ ref,
119
+ "data-rendra": code,
120
+ className: classes,
121
+ ...props,
122
+ children
123
+ });
124
+ const leading = loading ? /* @__PURE__ */ jsx(Spinner, { size: size === "lg" ? "md" : "sm" }) : icon;
125
+ return /* @__PURE__ */ jsxs("button", {
126
+ ref,
127
+ type,
128
+ "data-rendra": code,
129
+ className: classes,
130
+ disabled: disabled || loading,
131
+ "aria-busy": loading || void 0,
132
+ ...props,
133
+ children: [
134
+ leading,
135
+ iconOnly ? loading ? null : children : children,
136
+ !iconOnly && iconRight
137
+ ]
138
+ });
139
+ });
140
+ //#endregion
141
+ export { usePrefersReducedMotion as i, buttonVariants as n, Spinner as r, Button as t };
142
+
143
+ //# sourceMappingURL=button-DIcpJwK9.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button-DIcpJwK9.js","names":[],"sources":["../src/hooks/use-reduced-motion.ts","../src/components/ui/spinner.tsx","../src/components/ui/button.tsx"],"sourcesContent":["import { useSyncExternalStore } from 'react'\n\n/*\n * Único hook de leitura de \"menos movimento\" do sistema operacional (prefers-reduced-motion).\n * Usado pelo Spinner e pelo Progress indeterminado para parar a animação sem depender só do\n * CSS, e assim ficar testável (mocke matchMedia para simular a preferência).\n */\n\nfunction subscribe(cb: () => void) {\n const mq = matchMedia('(prefers-reduced-motion: reduce)')\n mq.addEventListener('change', cb)\n return () => mq.removeEventListener('change', cb)\n}\n\nfunction getCurrent() {\n return matchMedia('(prefers-reduced-motion: reduce)').matches\n}\n\nexport function usePrefersReducedMotion() {\n return useSyncExternalStore(subscribe, getCurrent, () => false)\n}\n","import { Loader2 } from 'lucide-react'\nimport { usePrefersReducedMotion } from '@/hooks/use-reduced-motion'\nimport { cn } from '@/lib/cn'\n\n/*\n * Indicador de carregamento único do sistema (A17 do plano da v2). Substitui qualquer\n * `Loader2 animate-spin` solto em Button, Input e Select. Sem label é decorativo\n * (aria-hidden); com label, anuncia o carregamento a quem usa leitor de tela. Para de girar\n * quando o sistema pede menos movimento.\n */\n\nexport interface SpinnerProps {\n size?: 'sm' | 'md' | 'lg'\n /** Nome do que está carregando. Vazio (padrão): decorativo, sem anúncio de leitor de tela. */\n label?: string\n className?: string\n}\n\nconst sizeClass: Record<NonNullable<SpinnerProps['size']>, string> = {\n sm: 'size-icon-sm',\n md: 'size-icon-md',\n lg: 'size-icon-lg',\n}\n\nexport function Spinner({ size = 'md', label, className }: SpinnerProps) {\n const reduced = usePrefersReducedMotion()\n const icon = (\n <Loader2 aria-hidden className={cn(sizeClass[size], reduced ? '' : 'animate-spin')} />\n )\n\n if (!label) {\n return (\n <span data-rendra=\"SPIN-001\" aria-hidden className={cn('inline-flex', className)}>\n {icon}\n </span>\n )\n }\n\n return (\n <span\n data-rendra=\"SPIN-001\"\n role=\"status\"\n className={cn('inline-flex items-center gap-2', className)}\n >\n {icon}\n <span className=\"sr-only\">{label}</span>\n </span>\n )\n}\n","import { cva, type VariantProps } from 'class-variance-authority'\nimport { Slot } from 'radix-ui'\nimport { forwardRef, type ButtonHTMLAttributes, type ReactNode } from 'react'\nimport { resolveCatalogCode } from '@/catalog/components'\nimport { Spinner } from '@/components/ui/spinner'\nimport { cn } from '@/lib/cn'\n\n/**\n * Botão único do sistema. Variantes, tamanho, ícone, só ícone, carregamento e\n * largura total são props: nunca crie outro arquivo de botão.\n * Altura vem de h-control-*: 44px ou mais no mobile, compacta a partir de md.\n */\nexport const buttonVariants = cva(\n 'inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 rounded-control font-medium whitespace-nowrap transition-[color,background-color,border-color,box-shadow,transform] duration-150 ease-out select-none active:scale-98 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 motion-reduce:active:scale-100 [&_svg]:pointer-events-none [&_svg]:shrink-0',\n {\n variants: {\n variant: {\n // Hover troca para a cor de hover da marca e eleva um nível; pressionar comprime.\n primary:\n 'bg-primary text-primary-foreground shadow-sm hover:bg-primary-hover hover:text-primary-hover-foreground hover:shadow-md active:bg-primary-hover active:text-primary-hover-foreground active:shadow-sm',\n secondary:\n 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary-hover hover:text-secondary-hover-foreground hover:shadow-md active:bg-secondary-hover active:text-secondary-hover-foreground active:shadow-sm',\n outline:\n 'border border-input bg-card text-foreground hover:border-primary hover:bg-primary-soft hover:text-primary-soft-foreground active:bg-primary-soft',\n // Transparentes: no hover, assumem a cor primária do template.\n ghost:\n 'text-foreground hover:bg-primary-soft hover:text-primary-soft-foreground active:bg-primary-soft',\n destructive:\n 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive-hover hover:shadow-md active:bg-destructive-hover active:shadow-sm',\n link: 'min-h-touch min-w-touch text-primary-text underline-offset-4 hover:text-primary-hover hover:underline md:min-h-0 md:min-w-0',\n },\n size: {\n sm: 'h-control-sm px-3 text-sm [&_svg]:size-icon-sm',\n md: 'h-control-md px-4 text-sm [&_svg]:size-icon-sm',\n lg: 'h-control-lg px-6 text-base [&_svg]:size-icon-md',\n },\n iconOnly: { true: 'px-0', false: '' },\n fullWidth: { true: 'w-full', false: '' },\n },\n compoundVariants: [\n { iconOnly: true, size: 'sm', className: 'w-control-sm' },\n { iconOnly: true, size: 'md', className: 'w-control-md' },\n { iconOnly: true, size: 'lg', className: 'w-control-lg' },\n { variant: 'link', className: 'h-auto px-0' },\n ],\n defaultVariants: { variant: 'primary', size: 'md', iconOnly: false, fullWidth: false },\n },\n)\n\ntype Variants = VariantProps<typeof buttonVariants>\n\nexport interface ButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>, Omit<Variants, 'iconOnly' | 'fullWidth'> {\n /** Ícone à esquerda do texto (ou o próprio conteúdo, com iconOnly). */\n icon?: ReactNode\n /** Ícone à direita do texto. */\n iconRight?: ReactNode\n /** Botão só com ícone: quadrado, e aria-label passa a ser obrigatório. */\n iconOnly?: boolean\n /** Mostra indicador, bloqueia cliques e marca aria-busy. */\n loading?: boolean\n /** Ocupa toda a largura do contêiner. */\n fullWidth?: boolean\n /** Renderiza o filho (ex.: <Link>) com a aparência de botão. */\n asChild?: boolean\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n {\n className,\n variant,\n size,\n icon,\n iconRight,\n iconOnly = false,\n loading = false,\n fullWidth = false,\n asChild = false,\n disabled,\n type = 'button',\n children,\n ...props\n },\n ref,\n) {\n if (import.meta.env.DEV && iconOnly && !props['aria-label']) {\n console.warn('Button com iconOnly precisa de aria-label.')\n }\n const classes = cn(buttonVariants({ variant, size, iconOnly, fullWidth }), className)\n const code = resolveCatalogCode('Button', { variant: variant ?? 'primary' })\n\n if (asChild) {\n return (\n <Slot.Root ref={ref} data-rendra={code} className={classes} {...props}>\n {children}\n </Slot.Root>\n )\n }\n\n // Ícone dentro do botão segue o tamanho do próprio botão (sm/md -> sm, lg -> md, como o\n // [&_svg]:size-icon-* de buttonVariants já fazia com o Loader2 solto).\n const leading = loading ? <Spinner size={size === 'lg' ? 'md' : 'sm'} /> : icon\n return (\n <button\n ref={ref}\n type={type}\n data-rendra={code}\n className={classes}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n {...props}\n >\n {leading}\n {iconOnly ? (loading ? null : children) : children}\n {!iconOnly && iconRight}\n </button>\n )\n})\n"],"mappings":";;;;;;;;;AAQA,SAAS,UAAU,IAAgB;CACjC,MAAM,KAAK,WAAW,kCAAkC;CACxD,GAAG,iBAAiB,UAAU,EAAE;CAChC,aAAa,GAAG,oBAAoB,UAAU,EAAE;AAClD;AAEA,SAAS,aAAa;CACpB,OAAO,WAAW,kCAAkC,CAAC,CAAC;AACxD;AAEA,SAAgB,0BAA0B;CACxC,OAAO,qBAAqB,WAAW,kBAAkB,KAAK;AAChE;;;ACFA,IAAM,YAA+D;CACnE,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,SAAgB,QAAQ,EAAE,OAAO,MAAM,OAAO,aAA2B;CACvE,MAAM,UAAU,wBAAwB;CACxC,MAAM,OACJ,oBAAC,SAAD;EAAS,eAAA;EAAY,WAAW,GAAG,UAAU,OAAO,UAAU,KAAK,cAAc;CAAI,CAAA;CAGvF,IAAI,CAAC,OACH,OACE,oBAAC,QAAD;EAAM,eAAY;EAAW,eAAA;EAAY,WAAW,GAAG,eAAe,SAAS;EAC5E,UAAA;CACG,CAAA;CAIV,OACE,qBAAC,QAAD;EACE,eAAY;EACZ,MAAK;EACL,WAAW,GAAG,kCAAkC,SAAS;EAH3D,UAAA,CAKG,MACD,oBAAC,QAAD;GAAM,WAAU;GAAW,UAAA;EAAY,CAAA,CACnC;;AAEV;;;;;;;;ACpCA,IAAa,iBAAiB,IAC5B,uaACA;CACE,UAAU;EACR,SAAS;GAEP,SACE;GACF,WACE;GACF,SACE;GAEF,OACE;GACF,aACE;GACF,MAAM;EACR;EACA,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;EACA,UAAU;GAAE,MAAM;GAAQ,OAAO;EAAG;EACpC,WAAW;GAAE,MAAM;GAAU,OAAO;EAAG;CACzC;CACA,kBAAkB;EAChB;GAAE,UAAU;GAAM,MAAM;GAAM,WAAW;EAAe;EACxD;GAAE,UAAU;GAAM,MAAM;GAAM,WAAW;EAAe;EACxD;GAAE,UAAU;GAAM,MAAM;GAAM,WAAW;EAAe;EACxD;GAAE,SAAS;GAAQ,WAAW;EAAc;CAC9C;CACA,iBAAiB;EAAE,SAAS;EAAW,MAAM;EAAM,UAAU;EAAO,WAAW;CAAM;AACvF,CACF;AAoBA,IAAa,SAAS,WAA2C,SAAS,OACxE,EACE,WACA,SACA,MACA,MACA,WACA,WAAW,OACX,UAAU,OACV,YAAY,OACZ,UAAU,OACV,UACA,OAAO,UACP,UACA,GAAG,SAEL,KACA;CAIA,MAAM,UAAU,GAAG,eAAe;EAAE;EAAS;EAAM;EAAU;CAAU,CAAC,GAAG,SAAS;CACpF,MAAM,OAAO,mBAAmB,UAAU,EAAE,SAAS,WAAW,UAAU,CAAC;CAE3E,IAAI,SACF,OACE,oBAAC,KAAK,MAAN;EAAgB;EAAK,eAAa;EAAM,WAAW;EAAS,GAAI;EAC7D;CACQ,CAAA;CAMf,MAAM,UAAU,UAAU,oBAAC,SAAD,EAAS,MAAM,SAAS,OAAO,OAAO,KAAO,CAAA,IAAI;CAC3E,OACE,qBAAC,UAAD;EACO;EACC;EACN,eAAa;EACb,WAAW;EACX,UAAU,YAAY;EACtB,aAAW,WAAW,KAAA;EACtB,GAAI;EAPN,UAAA;GASG;GACA,WAAY,UAAU,OAAO,WAAY;GACzC,CAAC,YAAY;EACR;;AAEZ,CAAC"}