@rendra-ui/web 2.3.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +107 -61
  2. package/bin/rendra.mjs +19 -7
  3. package/dist/base.css +33 -1
  4. package/dist/{button-DWhICtIG.js → button-BzJgR2gH.js} +86 -21
  5. package/dist/button-BzJgR2gH.js.map +1 -0
  6. package/dist/chart.js +61 -15
  7. package/dist/chart.js.map +1 -1
  8. package/dist/cli/auditar.js +66 -16
  9. package/dist/cli/auditar.js.map +1 -1
  10. package/dist/cli/codigos.js +2 -2
  11. package/dist/cli/executar-auditar.js +634 -0
  12. package/dist/cli/executar-auditar.js.map +1 -0
  13. package/dist/cli/help.js +7 -2
  14. package/dist/cli/help.js.map +1 -1
  15. package/dist/cli/trocar.js +2 -2
  16. package/dist/cli/typescript-loader.js +1 -1
  17. package/dist/{cn-DDZQKUVV.js → cn-Cw7M5kEP.js} +2 -2
  18. package/dist/{cn-DDZQKUVV.js.map → cn-Cw7M5kEP.js.map} +1 -1
  19. package/dist/{components-Cq_PmN4y.js → components-DkpspH9h.js} +21 -4
  20. package/dist/components-DkpspH9h.js.map +1 -0
  21. package/dist/components.css +274 -32
  22. package/dist/document-viewer.js +6 -6
  23. package/dist/document-viewer.js.map +1 -1
  24. package/dist/{empty-state-C491qfzf.js → empty-state-Cdb1vkMT.js} +81 -37
  25. package/dist/empty-state-Cdb1vkMT.js.map +1 -0
  26. package/dist/features-max--5VEt6M7.js +3 -0
  27. package/dist/index.js +1170 -390
  28. package/dist/index.js.map +1 -1
  29. package/dist/motion-context-5BRIQAJm.js +107 -0
  30. package/dist/motion-context-5BRIQAJm.js.map +1 -0
  31. package/dist/{rendra-provider-BRtk5Qa1.js → rendra-provider-CRe0XdOU.js} +9 -5
  32. package/dist/rendra-provider-CRe0XdOU.js.map +1 -0
  33. package/dist/rich-text-editor.js +4 -4
  34. package/dist/router-bridge.js +5 -4
  35. package/dist/router-bridge.js.map +1 -1
  36. package/dist/tokens.css +73 -15
  37. package/dist/tooltip-BAMSaGbS.js +224 -0
  38. package/dist/tooltip-BAMSaGbS.js.map +1 -0
  39. package/dist/types/components/app-shell/app-shell.d.ts +22 -2
  40. package/dist/types/components/app-shell/shell-context.d.ts +7 -1
  41. package/dist/types/components/app-shell/types.d.ts +23 -0
  42. package/dist/types/components/layout/page-header.d.ts +17 -1
  43. package/dist/types/components/rendra-provider.d.ts +7 -1
  44. package/dist/types/components/rendra-router-bridge.d.ts +3 -1
  45. package/dist/types/components/ui/accordion.d.ts +1 -1
  46. package/dist/types/components/ui/badge.d.ts +1 -1
  47. package/dist/types/components/ui/brand-feedback-icon.d.ts +20 -3
  48. package/dist/types/components/ui/button-group.d.ts +8 -1
  49. package/dist/types/components/ui/button.d.ts +1 -1
  50. package/dist/types/components/ui/dropdown-menu.d.ts +5 -5
  51. package/dist/types/components/ui/empty-state.d.ts +4 -0
  52. package/dist/types/components/ui/error-page.d.ts +6 -1
  53. package/dist/types/components/ui/modal.d.ts +4 -0
  54. package/dist/types/components/ui/picker-panel.d.ts +1 -1
  55. package/dist/types/components/ui/popover.d.ts +3 -3
  56. package/dist/types/components/ui/radio-group.d.ts +1 -1
  57. package/dist/types/components/ui/skeleton.d.ts +5 -1
  58. package/dist/types/components/ui/stat-card.d.ts +1 -1
  59. package/dist/types/components/ui/table.d.ts +0 -6
  60. package/dist/types/components/ui/tooltip.d.ts +1 -1
  61. package/dist/types/components/ui/wizard.d.ts +14 -1
  62. package/dist/types/hooks/use-reduced-motion.d.ts +3 -0
  63. package/dist/types/index.d.ts +1 -0
  64. package/dist/types/lib/initials.d.ts +2 -0
  65. package/dist/types/lib/motion/count.d.ts +17 -0
  66. package/dist/types/lib/motion/features-max.d.ts +1 -0
  67. package/dist/types/lib/motion/index.d.ts +5 -0
  68. package/dist/types/lib/motion/motion-context.d.ts +43 -0
  69. package/dist/types/lib/motion/native-events.d.ts +16 -0
  70. package/dist/types/lib/motion/presets.d.ts +92 -0
  71. package/dist/types/lib/motion/reorder.d.ts +7 -0
  72. package/dist/types/lib/motion/tokens.d.ts +66 -0
  73. package/dist/types/lib/motion/use-motion-presets.d.ts +8 -0
  74. package/dist/{use-breakpoint-C3ivDt2R.js → use-breakpoint-O9eqFmsF.js} +2 -2
  75. package/dist/{use-breakpoint-C3ivDt2R.js.map → use-breakpoint-O9eqFmsF.js.map} +1 -1
  76. package/dist/use-motion-presets-BrkgL8lG.js +401 -0
  77. package/dist/use-motion-presets-BrkgL8lG.js.map +1 -0
  78. package/dist/widget-grid.js +3 -3
  79. package/package.json +4 -1
  80. package/dist/button-DWhICtIG.js.map +0 -1
  81. package/dist/components-Cq_PmN4y.js.map +0 -1
  82. package/dist/empty-state-C491qfzf.js.map +0 -1
  83. package/dist/rendra-provider-BRtk5Qa1.js.map +0 -1
  84. package/dist/tooltip-DsNlnBSY.js +0 -105
  85. package/dist/tooltip-DsNlnBSY.js.map +0 -1
@@ -1,4 +1,4 @@
1
- /*! Rendra Design System v2.3.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
1
+ /*! Rendra Design System v2.5.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
2
 
3
3
  @layer properties {
4
4
  @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or
@@ -13,6 +13,11 @@
13
13
  --tw-scale-x: 1;
14
14
  --tw-scale-y: 1;
15
15
  --tw-scale-z: 1;
16
+ --tw-rotate-x: initial;
17
+ --tw-rotate-y: initial;
18
+ --tw-rotate-z: initial;
19
+ --tw-skew-x: initial;
20
+ --tw-skew-y: initial;
16
21
  --tw-pan-x: initial;
17
22
  --tw-pan-y: initial;
18
23
  --tw-pinch-zoom: initial;
@@ -43,9 +48,6 @@
43
48
  --tw-ring-offset-color: #fff;
44
49
  --tw-ring-offset-shadow: 0 0 #0000;
45
50
  --tw-outline-style: solid;
46
- --tw-duration: initial;
47
- --tw-ease: initial;
48
- --tw-content: '';
49
51
  --tw-blur: initial;
50
52
  --tw-brightness: initial;
51
53
  --tw-contrast: initial;
@@ -59,6 +61,9 @@
59
61
  --tw-drop-shadow-color: initial;
60
62
  --tw-drop-shadow-alpha: 100%;
61
63
  --tw-drop-shadow-size: initial;
64
+ --tw-duration: initial;
65
+ --tw-ease: initial;
66
+ --tw-content: '';
62
67
  --tw-animation-delay: 0s;
63
68
  --tw-animation-direction: normal;
64
69
  --tw-animation-duration: initial;
@@ -84,6 +89,9 @@
84
89
  .\@container {
85
90
  container-type: inline-size;
86
91
  }
92
+ .pointer-events-auto {
93
+ pointer-events: auto;
94
+ }
87
95
  .pointer-events-none {
88
96
  pointer-events: none;
89
97
  }
@@ -96,6 +104,36 @@
96
104
  .visible {
97
105
  visibility: visible;
98
106
  }
107
+ .skeleton-shimmer {
108
+ position: relative;
109
+ overflow: hidden;
110
+ &::after {
111
+ content: '';
112
+ position: absolute;
113
+ inset: 0;
114
+ background-image: linear-gradient(
115
+ 90deg,
116
+ transparent,
117
+ var(--rendra-muted-foreground),
118
+ transparent
119
+ );
120
+ @supports (color: color-mix(in lab, red, red)) {
121
+ background-image: linear-gradient(
122
+ 90deg,
123
+ transparent,
124
+ color-mix(in oklab, var(--rendra-muted-foreground) 12%, transparent),
125
+ transparent
126
+ );
127
+ }
128
+ transform: translateX(-100%);
129
+ animation: rd-shimmer var(--rendra-duration-pulse) var(--rendra-ease-move) infinite;
130
+ }
131
+ @media (prefers-reduced-motion: reduce) {
132
+ &::after {
133
+ animation: none;
134
+ }
135
+ }
136
+ }
99
137
  .sr-only {
100
138
  position: absolute;
101
139
  width: 1px;
@@ -153,6 +191,9 @@
153
191
  .calendar-now {
154
192
  top: calc(var(--from, 0) * 3rem);
155
193
  }
194
+ .top-0 {
195
+ top: 0px;
196
+ }
156
197
  .top-1 {
157
198
  top: 0.25rem;
158
199
  }
@@ -210,6 +251,12 @@
210
251
  .left-4 {
211
252
  left: 1rem;
212
253
  }
254
+ .isolate {
255
+ isolation: isolate;
256
+ }
257
+ .-z-10 {
258
+ z-index: calc(10 * -1);
259
+ }
213
260
  .z-10 {
214
261
  z-index: 10;
215
262
  }
@@ -234,6 +281,9 @@
234
281
  .col-span-7 {
235
282
  grid-column: span 7 / span 7;
236
283
  }
284
+ .col-span-10 {
285
+ grid-column: span 10 / span 10;
286
+ }
237
287
  .container {
238
288
  width: 100%;
239
289
  @media (width >= 40rem) {
@@ -252,6 +302,9 @@
252
302
  max-width: 96rem;
253
303
  }
254
304
  }
305
+ .m-0 {
306
+ margin: 0px;
307
+ }
255
308
  .m-auto {
256
309
  margin: auto;
257
310
  }
@@ -320,6 +373,9 @@
320
373
  margin-bottom: -1px;
321
374
  margin-bottom: calc(1px * -1);
322
375
  }
376
+ .mb-0 {
377
+ margin-bottom: 0px;
378
+ }
323
379
  .mb-1 {
324
380
  margin-bottom: 0.25rem;
325
381
  }
@@ -751,6 +807,15 @@
751
807
  transform-origin: 50% 56.604%;
752
808
  transition: transform 700ms cubic-bezier(0.22, 1, 0.36, 1);
753
809
  }
810
+ .origin-\(--radix-dropdown-menu-content-transform-origin\) {
811
+ transform-origin: var(--radix-dropdown-menu-content-transform-origin);
812
+ }
813
+ .origin-\(--radix-popover-content-transform-origin\) {
814
+ transform-origin: var(--radix-popover-content-transform-origin);
815
+ }
816
+ .origin-\(--radix-tooltip-content-transform-origin\) {
817
+ transform-origin: var(--radix-tooltip-content-transform-origin);
818
+ }
754
819
  .origin-center {
755
820
  transform-origin: center;
756
821
  }
@@ -762,10 +827,10 @@
762
827
  --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);
763
828
  translate: var(--tw-translate-x) var(--tw-translate-y);
764
829
  }
765
- .scale-0 {
766
- --tw-scale-x: 0%;
767
- --tw-scale-y: 0%;
768
- --tw-scale-z: 0%;
830
+ .scale-90 {
831
+ --tw-scale-x: 90%;
832
+ --tw-scale-y: 90%;
833
+ --tw-scale-z: 90%;
769
834
  scale: var(--tw-scale-x) var(--tw-scale-y);
770
835
  }
771
836
  .rotate-90 {
@@ -778,14 +843,22 @@
778
843
  transform: translate(-50%, -50%) translate(var(--crop-x, 0px), var(--crop-y, 0px))
779
844
  scale(var(--crop-scale, 1));
780
845
  }
846
+ .transform {
847
+ transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,)
848
+ var(--tw-skew-y,);
849
+ }
781
850
  .progress-slide {
782
- animation: rd-progress-slide 1.1s ease-in-out infinite;
851
+ animation: rd-progress-slide var(--rendra-duration-pulse) linear infinite;
783
852
  @media (prefers-reduced-motion: reduce) {
784
853
  animation: none;
785
854
  }
786
855
  }
787
856
  .animate-draw {
788
- animation: rd-draw 420ms cubic-bezier(0.22, 1, 0.36, 1) 200ms both;
857
+ animation: rd-draw var(--rendra-duration-draw) var(--rendra-ease-out)
858
+ var(--rendra-duration-base) both;
859
+ }
860
+ .animate-encaixe {
861
+ animation: rd-encaixe calc(var(--rendra-duration-fast) * 2) var(--rendra-ease-out) both;
789
862
  }
790
863
  .animate-in {
791
864
  animation: enter var(--tw-animation-duration, var(--tw-duration, 0.15s)) var(--tw-ease, ease)
@@ -793,13 +866,14 @@
793
866
  var(--tw-animation-direction, normal) var(--tw-animation-fill-mode, none);
794
867
  }
795
868
  .animate-pop {
796
- animation: rd-pop 420ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
869
+ animation: rd-pop var(--rendra-duration-draw) var(--rendra-ease-spring) both;
797
870
  }
798
871
  .animate-pulse {
799
872
  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
800
873
  }
801
874
  .animate-shake {
802
- animation: rd-shake 420ms cubic-bezier(0.65, 0, 0.35, 1) 620ms both;
875
+ animation: rd-shake var(--rendra-duration-draw) var(--rendra-ease-in-out)
876
+ calc(var(--rendra-duration-draw) + var(--rendra-duration-base)) both;
803
877
  }
804
878
  .animate-spin {
805
879
  animation: spin 1s linear infinite;
@@ -1374,6 +1448,9 @@
1374
1448
  .px-6 {
1375
1449
  padding-inline: 1.5rem;
1376
1450
  }
1451
+ .py-0 {
1452
+ padding-block: 0px;
1453
+ }
1377
1454
  .py-1 {
1378
1455
  padding-block: 0.25rem;
1379
1456
  }
@@ -1771,6 +1848,40 @@
1771
1848
  outline-style: var(--tw-outline-style);
1772
1849
  outline-width: 1px;
1773
1850
  }
1851
+ .blur {
1852
+ --tw-blur: blur(8px);
1853
+ filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,)
1854
+ var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,)
1855
+ var(--tw-drop-shadow,);
1856
+ }
1857
+ .transition {
1858
+ transition-property:
1859
+ color,
1860
+ background-color,
1861
+ border-color,
1862
+ outline-color,
1863
+ text-decoration-color,
1864
+ fill,
1865
+ stroke,
1866
+ --tw-gradient-from,
1867
+ --tw-gradient-via,
1868
+ --tw-gradient-to,
1869
+ opacity,
1870
+ box-shadow,
1871
+ transform,
1872
+ translate,
1873
+ scale,
1874
+ rotate,
1875
+ filter,
1876
+ -webkit-backdrop-filter,
1877
+ backdrop-filter,
1878
+ display,
1879
+ content-visibility,
1880
+ overlay,
1881
+ pointer-events;
1882
+ transition-timing-function: var(--tw-ease, cubic-bezier(0.4, 0, 0.2, 1));
1883
+ transition-duration: var(--tw-duration, 150ms);
1884
+ }
1774
1885
  .transition-\[border-color\,box-shadow\,background-color\] {
1775
1886
  transition-property: border-color, box-shadow, background-color;
1776
1887
  transition-timing-function: var(--tw-ease, cubic-bezier(0.4, 0, 0.2, 1));
@@ -1791,11 +1902,26 @@
1791
1902
  transition-timing-function: var(--tw-ease, cubic-bezier(0.4, 0, 0.2, 1));
1792
1903
  transition-duration: var(--tw-duration, 150ms);
1793
1904
  }
1905
+ .transition-\[color\,background-color\,border-color\,box-shadow\] {
1906
+ transition-property: color, background-color, border-color, box-shadow;
1907
+ transition-timing-function: var(--tw-ease, cubic-bezier(0.4, 0, 0.2, 1));
1908
+ transition-duration: var(--tw-duration, 150ms);
1909
+ }
1794
1910
  .transition-\[filter\] {
1795
1911
  transition-property: filter;
1796
1912
  transition-timing-function: var(--tw-ease, cubic-bezier(0.4, 0, 0.2, 1));
1797
1913
  transition-duration: var(--tw-duration, 150ms);
1798
1914
  }
1915
+ .transition-\[transform\,opacity\] {
1916
+ transition-property: transform, opacity;
1917
+ transition-timing-function: var(--tw-ease, cubic-bezier(0.4, 0, 0.2, 1));
1918
+ transition-duration: var(--tw-duration, 150ms);
1919
+ }
1920
+ .transition-\[translate\] {
1921
+ transition-property: translate;
1922
+ transition-timing-function: var(--tw-ease, cubic-bezier(0.4, 0, 0.2, 1));
1923
+ transition-duration: var(--tw-duration, 150ms);
1924
+ }
1799
1925
  .transition-\[width\,box-shadow\] {
1800
1926
  transition-property: width, box-shadow;
1801
1927
  transition-timing-function: var(--tw-ease, cubic-bezier(0.4, 0, 0.2, 1));
@@ -1806,11 +1932,6 @@
1806
1932
  transition-timing-function: var(--tw-ease, cubic-bezier(0.4, 0, 0.2, 1));
1807
1933
  transition-duration: var(--tw-duration, 150ms);
1808
1934
  }
1809
- .transition-all {
1810
- transition-property: all;
1811
- transition-timing-function: var(--tw-ease, cubic-bezier(0.4, 0, 0.2, 1));
1812
- transition-duration: var(--tw-duration, 150ms);
1813
- }
1814
1935
  .transition-colors {
1815
1936
  transition-property:
1816
1937
  color, background-color, border-color, outline-color, text-decoration-color, fill, stroke,
@@ -1828,6 +1949,18 @@
1828
1949
  transition-timing-function: var(--tw-ease, cubic-bezier(0.4, 0, 0.2, 1));
1829
1950
  transition-duration: var(--tw-duration, 150ms);
1830
1951
  }
1952
+ .duration-\(--rendra-duration-base\) {
1953
+ --tw-duration: var(--rendra-duration-base);
1954
+ transition-duration: var(--rendra-duration-base);
1955
+ }
1956
+ .duration-\(--rendra-duration-fast\) {
1957
+ --tw-duration: var(--rendra-duration-fast);
1958
+ transition-duration: var(--rendra-duration-fast);
1959
+ }
1960
+ .duration-\(--rendra-duration-press\) {
1961
+ --tw-duration: var(--rendra-duration-press);
1962
+ transition-duration: var(--rendra-duration-press);
1963
+ }
1831
1964
  .duration-150 {
1832
1965
  --tw-duration: 150ms;
1833
1966
  transition-duration: 150ms;
@@ -1836,17 +1969,17 @@
1836
1969
  --tw-duration: 200ms;
1837
1970
  transition-duration: 200ms;
1838
1971
  }
1839
- .duration-300 {
1840
- --tw-duration: 300ms;
1841
- transition-duration: 300ms;
1972
+ .ease-linear {
1973
+ --tw-ease: linear;
1974
+ transition-timing-function: linear;
1842
1975
  }
1843
- .duration-700 {
1844
- --tw-duration: 700ms;
1845
- transition-duration: 700ms;
1976
+ .ease-move {
1977
+ --tw-ease: var(--rendra-ease-move);
1978
+ transition-timing-function: var(--rendra-ease-move);
1846
1979
  }
1847
1980
  .ease-out {
1848
- --tw-ease: cubic-bezier(0.22, 1, 0.36, 1);
1849
- transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
1981
+ --tw-ease: var(--rendra-ease-out);
1982
+ transition-timing-function: var(--rendra-ease-out);
1850
1983
  }
1851
1984
  .fade-in-0 {
1852
1985
  --tw-enter-opacity: calc(0/100);
@@ -1860,6 +1993,10 @@
1860
1993
  -webkit-user-select: none;
1861
1994
  user-select: none;
1862
1995
  }
1996
+ .tabs-clip {
1997
+ clip-path: inset(0 var(--tabs-r, 100%) 0 var(--tabs-l, 0px));
1998
+ transition: clip-path var(--rendra-duration-move) var(--rendra-ease-move);
1999
+ }
1863
2000
  .zoom-in-95 {
1864
2001
  --tw-enter-scale: calc(95 * 1%);
1865
2002
  --tw-enter-scale: 0.95;
@@ -1909,6 +2046,9 @@
1909
2046
  ) {
1910
2047
  color: var(--rendra-primary-foreground);
1911
2048
  }
2049
+ .group-data-\[state\=checked\]\:opacity-100:is(:where(.group)[data-state='checked'] *) {
2050
+ opacity: 100%;
2051
+ }
1912
2052
  .group-data-\[state\=open\]\:hidden:is(:where(.group)[data-state='open'] *) {
1913
2053
  display: none;
1914
2054
  }
@@ -2171,9 +2311,15 @@
2171
2311
  --tw-ring-color: color-mix(in oklab, var(--rendra-ring) 25%, transparent);
2172
2312
  }
2173
2313
  }
2314
+ .focus-visible\:cursor-pointer:focus-visible {
2315
+ cursor: pointer;
2316
+ }
2174
2317
  .focus-visible\:bg-accent:focus-visible {
2175
2318
  background-color: var(--rendra-accent);
2176
2319
  }
2320
+ .focus-visible\:opacity-100:focus-visible {
2321
+ opacity: 100%;
2322
+ }
2177
2323
  .focus-visible\:ring-2:focus-visible {
2178
2324
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width))
2179
2325
  var(--tw-ring-color, currentcolor);
@@ -2202,10 +2348,16 @@
2202
2348
  --tw-scale-z: 95%;
2203
2349
  scale: var(--tw-scale-x) var(--tw-scale-y);
2204
2350
  }
2205
- .active\:scale-98:active {
2206
- --tw-scale-x: 98%;
2207
- --tw-scale-y: 98%;
2208
- --tw-scale-z: 98%;
2351
+ .active\:scale-97:active {
2352
+ --tw-scale-x: 97%;
2353
+ --tw-scale-y: 97%;
2354
+ --tw-scale-z: 97%;
2355
+ scale: var(--tw-scale-x) var(--tw-scale-y);
2356
+ }
2357
+ .active\:scale-100:active {
2358
+ --tw-scale-x: 100%;
2359
+ --tw-scale-y: 100%;
2360
+ --tw-scale-z: 100%;
2209
2361
  scale: var(--tw-scale-x) var(--tw-scale-y);
2210
2362
  }
2211
2363
  .active\:cursor-grabbing:active {
@@ -2410,9 +2562,13 @@
2410
2562
  .data-\[state\=checked\]\:ring-primary[data-state='checked'] {
2411
2563
  --tw-ring-color: var(--rendra-primary);
2412
2564
  }
2413
- .data-\[state\=checked\]\:zoom-in-50[data-state='checked'] {
2414
- --tw-enter-scale: calc(50 * 1%);
2415
- --tw-enter-scale: 0.5;
2565
+ .data-\[state\=checked\]\:duration-\(--rendra-duration-fast\)[data-state='checked'] {
2566
+ --tw-duration: var(--rendra-duration-fast);
2567
+ transition-duration: var(--rendra-duration-fast);
2568
+ }
2569
+ .data-\[state\=checked\]\:zoom-in-90[data-state='checked'] {
2570
+ --tw-enter-scale: calc(90 * 1%);
2571
+ --tw-enter-scale: 0.9;
2416
2572
  }
2417
2573
  .data-\[state\=closed\]\:animate-accordion-up[data-state='closed'] {
2418
2574
  animation: accordion-up var(--tw-animation-duration, var(--tw-duration, 0.2s))
@@ -2429,6 +2585,10 @@
2429
2585
  var(--tw-animation-delay, 0s) var(--tw-animation-iteration-count, 1)
2430
2586
  var(--tw-animation-direction, normal) var(--tw-animation-fill-mode, none);
2431
2587
  }
2588
+ .data-\[state\=closed\]\:duration-\(--rendra-duration-fast\)[data-state='closed'] {
2589
+ --tw-duration: var(--rendra-duration-fast);
2590
+ transition-duration: var(--rendra-duration-fast);
2591
+ }
2432
2592
  .data-\[state\=closed\]\:fade-out-0[data-state='closed'] {
2433
2593
  --tw-exit-opacity: calc(0/100);
2434
2594
  --tw-exit-opacity: 0;
@@ -2455,6 +2615,9 @@
2455
2615
  .data-\[state\=indeterminate\]\:text-primary-foreground[data-state='indeterminate'] {
2456
2616
  color: var(--rendra-primary-foreground);
2457
2617
  }
2618
+ .data-\[state\=instant-open\]\:animate-none[data-state='instant-open'] {
2619
+ animation: none;
2620
+ }
2458
2621
  .data-\[state\=open\]\:animate-accordion-down[data-state='open'] {
2459
2622
  animation: accordion-down var(--tw-animation-duration, var(--tw-duration, 0.2s))
2460
2623
  var(--tw-ease, ease-out) var(--tw-animation-delay, 0s) var(--tw-animation-iteration-count, 1)
@@ -2512,6 +2675,17 @@
2512
2675
  }
2513
2676
  }
2514
2677
  @media (width < 48rem) {
2678
+ .max-md\:sr-only {
2679
+ position: absolute;
2680
+ width: 1px;
2681
+ height: 1px;
2682
+ padding: 0;
2683
+ margin: -1px;
2684
+ overflow: hidden;
2685
+ clip-path: inset(50%);
2686
+ white-space: nowrap;
2687
+ border-width: 0;
2688
+ }
2515
2689
  .max-md\:-my-3 {
2516
2690
  margin-block: calc(0.75rem * -1);
2517
2691
  }
@@ -2528,6 +2702,9 @@
2528
2702
  .max-md\:min-h-touch {
2529
2703
  min-height: 2.75rem;
2530
2704
  }
2705
+ .max-md\:flex-none {
2706
+ flex: none;
2707
+ }
2531
2708
  .max-md\:before\:absolute::before {
2532
2709
  content: var(--tw-content);
2533
2710
  position: absolute;
@@ -2602,6 +2779,17 @@
2602
2779
  }
2603
2780
  }
2604
2781
  @media (width >= 48rem) {
2782
+ .md\:sr-only {
2783
+ position: absolute;
2784
+ width: 1px;
2785
+ height: 1px;
2786
+ padding: 0;
2787
+ margin: -1px;
2788
+ overflow: hidden;
2789
+ clip-path: inset(50%);
2790
+ white-space: nowrap;
2791
+ border-width: 0;
2792
+ }
2605
2793
  .md\:inset-6 {
2606
2794
  inset: 1.5rem;
2607
2795
  }
@@ -2635,6 +2823,9 @@
2635
2823
  .md\:-mb-4 {
2636
2824
  margin-bottom: calc(1rem * -1);
2637
2825
  }
2826
+ .md\:mb-0 {
2827
+ margin-bottom: 0px;
2828
+ }
2638
2829
  .md\:ml-auto {
2639
2830
  margin-left: auto;
2640
2831
  }
@@ -2816,6 +3007,9 @@
2816
3007
  .md\:px-6 {
2817
3008
  padding-inline: 1.5rem;
2818
3009
  }
3010
+ .md\:py-0 {
3011
+ padding-block: 0px;
3012
+ }
2819
3013
  .md\:py-1 {
2820
3014
  padding-block: 0.25rem;
2821
3015
  }
@@ -2834,6 +3028,9 @@
2834
3028
  .md\:pt-2 {
2835
3029
  padding-top: 0.5rem;
2836
3030
  }
3031
+ .md\:pt-4 {
3032
+ padding-top: 1rem;
3033
+ }
2837
3034
  .md\:pt-6 {
2838
3035
  padding-top: 1.5rem;
2839
3036
  }
@@ -3142,6 +3339,9 @@
3142
3339
  .\[\&\>\*\]\:min-h-0 > * {
3143
3340
  min-height: 0px;
3144
3341
  }
3342
+ .\[\&\>\*\]\:w-full > * {
3343
+ width: 100%;
3344
+ }
3145
3345
  .\[\&\>\*\]\:flex-1 > * {
3146
3346
  flex: 1;
3147
3347
  }
@@ -3155,14 +3355,30 @@
3155
3355
  var(--tw-ring-shadow), var(--tw-shadow);
3156
3356
  }
3157
3357
  @media (width >= 48rem) {
3358
+ .md\:\[\&\>\*\]\:w-auto > * {
3359
+ width: auto;
3360
+ }
3158
3361
  .md\:\[\&\>\*\]\:flex-none > * {
3159
3362
  flex: none;
3160
3363
  }
3161
3364
  }
3365
+ .\[\&\>\*\:first-child\]\:rounded-t-control > :first-child {
3366
+ border-top-left-radius: var(--rendra-shape-control);
3367
+ border-top-right-radius: var(--rendra-shape-control);
3368
+ }
3162
3369
  .\[\&\>\*\:first-child\]\:rounded-l-control > :first-child {
3163
3370
  border-top-left-radius: var(--rendra-shape-control);
3164
3371
  border-bottom-left-radius: var(--rendra-shape-control);
3165
3372
  }
3373
+ @media (width >= 48rem) {
3374
+ .md\:\[\&\>\*\:first-child\]\:rounded-l-control > :first-child {
3375
+ border-top-left-radius: var(--rendra-shape-control);
3376
+ border-bottom-left-radius: var(--rendra-shape-control);
3377
+ }
3378
+ .md\:\[\&\>\*\:first-child\]\:rounded-tr-none > :first-child {
3379
+ border-top-right-radius: 0;
3380
+ }
3381
+ }
3166
3382
  .\[\&\>\*\:focus-visible\]\:z-10 > :focus-visible {
3167
3383
  z-index: 10;
3168
3384
  }
@@ -3170,10 +3386,36 @@
3170
3386
  border-top-right-radius: var(--rendra-shape-control);
3171
3387
  border-bottom-right-radius: var(--rendra-shape-control);
3172
3388
  }
3389
+ .\[\&\>\*\:last-child\]\:rounded-b-control > :last-child {
3390
+ border-bottom-right-radius: var(--rendra-shape-control);
3391
+ border-bottom-left-radius: var(--rendra-shape-control);
3392
+ }
3393
+ @media (width >= 48rem) {
3394
+ .md\:\[\&\>\*\:last-child\]\:rounded-r-control > :last-child {
3395
+ border-top-right-radius: var(--rendra-shape-control);
3396
+ border-bottom-right-radius: var(--rendra-shape-control);
3397
+ }
3398
+ .md\:\[\&\>\*\:last-child\]\:rounded-bl-none > :last-child {
3399
+ border-bottom-left-radius: 0;
3400
+ }
3401
+ }
3402
+ .\[\&\>\*\:not\(\:first-child\)\]\:-mt-px > :not(:first-child) {
3403
+ margin-top: -1px;
3404
+ margin-top: calc(1px * -1);
3405
+ }
3173
3406
  .\[\&\>\*\:not\(\:first-child\)\]\:-ml-px > :not(:first-child) {
3174
3407
  margin-left: -1px;
3175
3408
  margin-left: calc(1px * -1);
3176
3409
  }
3410
+ @media (width >= 48rem) {
3411
+ .md\:\[\&\>\*\:not\(\:first-child\)\]\:mt-0 > :not(:first-child) {
3412
+ margin-top: 0px;
3413
+ }
3414
+ .md\:\[\&\>\*\:not\(\:first-child\)\]\:-ml-px > :not(:first-child) {
3415
+ margin-left: -1px;
3416
+ margin-left: calc(1px * -1);
3417
+ }
3418
+ }
3177
3419
  .\[\&\>button\]\:rounded-none > button {
3178
3420
  border-radius: 0;
3179
3421
  }
@@ -1,10 +1,10 @@
1
- /*! Rendra Design System v2.3.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
- import { t as cn } from "./cn-DDZQKUVV.js";
3
- import { t as Button } from "./button-DWhICtIG.js";
4
- import { t as EmptyState } from "./empty-state-C491qfzf.js";
1
+ /*! Rendra Design System v2.5.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
+ import { t as cn } from "./cn-Cw7M5kEP.js";
3
+ import { t as Button } from "./button-BzJgR2gH.js";
4
+ import { t as EmptyState } from "./empty-state-Cdb1vkMT.js";
5
5
  import { ChevronLeft, ChevronRight, ExternalLink, ZoomIn, ZoomOut } from "lucide-react";
6
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
6
  import { useEffect, useRef, useState } from "react";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  //#region src/components/ui/document-viewer.tsx
9
9
  var MIN_SCALE = .25;
10
10
  var MAX_SCALE = 3;
@@ -129,7 +129,7 @@ function DocumentViewer({ url, title, className, emptyTitle = "Nenhum documento
129
129
  })
130
130
  })
131
131
  }),
132
- status === "ready" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
132
+ status === "ready" && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
133
133
  className: "flex shrink-0 items-center justify-between gap-3 border-b bg-card px-3 py-2",
134
134
  children: [/* @__PURE__ */ jsxs("div", {
135
135
  className: "flex items-center gap-1",
@@ -1 +1 @@
1
- {"version":3,"file":"document-viewer.js","names":[],"sources":["../src/components/ui/document-viewer.tsx"],"sourcesContent":["import { ChevronLeft, ChevronRight, ExternalLink, ZoomIn, ZoomOut } from 'lucide-react'\nimport { useEffect, useRef, useState } from 'react'\nimport { Button } from '@/components/ui/button'\nimport { EmptyState } from '@/components/ui/empty-state'\nimport { cn } from '@/lib/cn'\n\n/*\n * Visualizador de documentos PDF. Carrega o pdfjs-dist sob demanda (import dinâmico), com o\n * worker também sob demanda, para o pacote principal nunca pagar o custo de quem não usa o\n * visualizador. url null é o estado vazio legítimo (nenhum documento escolhido ainda). Falha\n * (CORS, arquivo inválido) é declarada, nunca uma tela em branco: sempre com o link \"Abrir em\n * nova aba\".\n */\n\n// pdfjs-dist é grande e só entra no bundle de quem realmente usa o DocumentViewer: os tipos\n// abaixo são só de compilação (import de tipo), o import de valor é sempre dinâmico (import()).\ntype PdfDocumentProxy = import('pdfjs-dist').PDFDocumentProxy\n// destroy() vive na tarefa de carregamento (o que getDocument devolve antes do .promise),\n// não no documento já resolvido: é ela que precisa ser guardada para liberar depois.\ntype PdfLoadingTask = import('pdfjs-dist').PDFDocumentLoadingTask\n\ntype Status = 'empty' | 'loading' | 'ready' | 'error'\n\nexport interface DocumentViewerProps {\n /** Endereço do PDF. null é o estado vazio legítimo (nenhum documento escolhido ainda). */\n url: string | null\n /** Nome acessível do documento (aria-label do visualizador). */\n title: string\n className?: string\n emptyTitle?: string\n emptyDescription?: string\n loadingLabel?: string\n errorTitle?: string\n errorDescription?: string\n openInNewTabLabel?: string\n zoomInLabel?: string\n zoomOutLabel?: string\n previousPageLabel?: string\n nextPageLabel?: string\n}\n\nconst MIN_SCALE = 0.25\nconst MAX_SCALE = 3\nconst ZOOM_STEP = 1.25\n\n/** Um visualizador de documento por tela; nunca crie um segundo para PDF. */\nexport function DocumentViewer({\n url,\n title,\n className,\n emptyTitle = 'Nenhum documento selecionado',\n emptyDescription = 'Escolha um arquivo PDF para visualizar aqui.',\n loadingLabel = 'Carregando documento...',\n errorTitle = 'Não foi possível abrir o documento',\n errorDescription = 'O arquivo pode estar indisponível, corrompido ou bloqueado por CORS.',\n openInNewTabLabel = 'Abrir em nova aba',\n zoomInLabel = 'Aumentar zoom',\n zoomOutLabel = 'Diminuir zoom',\n previousPageLabel = 'Página anterior',\n nextPageLabel = 'Próxima página',\n}: DocumentViewerProps) {\n const [status, setStatus] = useState<Status>(url ? 'loading' : 'empty')\n const [page, setPage] = useState(1)\n const [numPages, setNumPages] = useState(0)\n const [scale, setScale] = useState(1)\n const [fitToWidth, setFitToWidth] = useState(true)\n const pdfRef = useRef<PdfDocumentProxy | null>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n const canvasRef = useRef<HTMLCanvasElement>(null)\n\n // Carrega o documento (ou reinicia o estado vazio) sempre que a url muda. Libera a tarefa\n // de carregamento (destroy) ao trocar de url e ao desmontar, para não vazar memória nem o\n // worker que o pdfjs sobe para cada documento.\n useEffect(() => {\n let cancelled = false\n let loadingTask: PdfLoadingTask | null = null\n pdfRef.current = null\n setPage(1)\n setNumPages(0)\n setFitToWidth(true)\n setScale(1)\n\n if (!url) {\n setStatus('empty')\n return\n }\n const targetUrl: string = url\n\n setStatus('loading')\n async function load() {\n try {\n const [pdfjsLib, workerModule] = await Promise.all([\n import('pdfjs-dist'),\n import('pdfjs-dist/build/pdf.worker.min.mjs?url'),\n ])\n pdfjsLib.GlobalWorkerOptions.workerSrc = workerModule.default\n if (cancelled) return\n loadingTask = pdfjsLib.getDocument({ url: targetUrl })\n const doc = await loadingTask.promise\n if (cancelled) return\n pdfRef.current = doc\n setNumPages(doc.numPages)\n setStatus('ready')\n } catch {\n if (cancelled) return\n setStatus('error')\n }\n }\n void load()\n return () => {\n cancelled = true\n void loadingTask?.destroy()\n }\n }, [url])\n\n // Desenha a página atual sempre que ela, o zoom ou o modo \"ajustar à largura\" mudam.\n useEffect(() => {\n if (status !== 'ready' || !pdfRef.current) return\n let cancelled = false\n async function draw() {\n const doc = pdfRef.current\n if (!doc) return\n const pdfPage = await doc.getPage(page)\n if (cancelled) return\n const natural = pdfPage.getViewport({ scale: 1 })\n const containerWidth = containerRef.current?.clientWidth ?? 0\n const effectiveScale =\n fitToWidth && containerWidth > 0 ? containerWidth / natural.width : scale\n const viewport = pdfPage.getViewport({ scale: effectiveScale })\n const canvas = canvasRef.current\n if (!canvas) return\n canvas.width = viewport.width\n canvas.height = viewport.height\n const ctx = canvas.getContext('2d')\n // Sem contexto 2D disponível (ambiente sem canvas real): mantém os controles\n // funcionando, só não desenha o pixel a pixel.\n if (!ctx) return\n await pdfPage.render({ canvas, canvasContext: ctx, viewport }).promise\n }\n void draw()\n return () => {\n cancelled = true\n }\n }, [status, page, scale, fitToWidth])\n\n const zoomIn = () => {\n setFitToWidth(false)\n setScale((s) => Math.min(MAX_SCALE, s * ZOOM_STEP))\n }\n const zoomOut = () => {\n setFitToWidth(false)\n setScale((s) => Math.max(MIN_SCALE, s / ZOOM_STEP))\n }\n\n return (\n <div\n data-rendra=\"DOC-001\"\n role=\"group\"\n aria-label={title}\n className={cn(\n 'flex h-viewer min-h-0 flex-col overflow-hidden rounded-surface border bg-card',\n className,\n )}\n >\n {status === 'empty' && (\n <EmptyState title={emptyTitle} description={emptyDescription} className=\"m-auto\" />\n )}\n\n {status === 'loading' && (\n <div\n className=\"m-auto flex flex-col items-center gap-2 px-4 py-8 text-sm text-muted-foreground\"\n role=\"status\"\n >\n {loadingLabel}\n </div>\n )}\n\n {status === 'error' && (\n <EmptyState\n type=\"error\"\n title={errorTitle}\n description={errorDescription}\n className=\"m-auto\"\n actions={\n url && (\n <Button variant=\"outline\" asChild>\n <a href={url} target=\"_blank\" rel=\"noreferrer\">\n <ExternalLink aria-hidden />\n {openInNewTabLabel}\n </a>\n </Button>\n )\n }\n />\n )}\n\n {status === 'ready' && (\n <>\n <div className=\"flex shrink-0 items-center justify-between gap-3 border-b bg-card px-3 py-2\">\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n aria-label={zoomOutLabel}\n icon={<ZoomOut />}\n onClick={zoomOut}\n />\n <span className=\"w-12 text-center text-xs text-muted-foreground tabular-nums\">\n {fitToWidth ? 'Ajustar' : `${Math.round(scale * 100)}%`}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n aria-label={zoomInLabel}\n icon={<ZoomIn />}\n onClick={zoomIn}\n />\n </div>\n {numPages > 1 && (\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n aria-label={previousPageLabel}\n icon={<ChevronLeft />}\n disabled={page <= 1}\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n />\n <span className=\"text-xs text-muted-foreground tabular-nums\" aria-live=\"polite\">\n {page} de {numPages}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n aria-label={nextPageLabel}\n icon={<ChevronRight />}\n disabled={page >= numPages}\n onClick={() => setPage((p) => Math.min(numPages, p + 1))}\n />\n </div>\n )}\n </div>\n <div\n ref={containerRef}\n className=\"flex min-h-0 flex-1 items-center justify-center overflow-auto bg-muted p-4\"\n >\n <canvas ref={canvasRef} className=\"max-w-full rounded-item bg-card shadow-sm\" />\n </div>\n </>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;AAyCA,IAAM,YAAY;AAClB,IAAM,YAAY;AAClB,IAAM,YAAY;;AAGlB,SAAgB,eAAe,EAC7B,KACA,OACA,WACA,aAAa,gCACb,mBAAmB,gDACnB,eAAe,2BACf,aAAa,sCACb,mBAAmB,wEACnB,oBAAoB,qBACpB,cAAc,iBACd,eAAe,iBACf,oBAAoB,mBACpB,gBAAgB,oBACM;CACtB,MAAM,CAAC,QAAQ,aAAa,SAAiB,MAAM,YAAY,OAAO;CACtE,MAAM,CAAC,MAAM,WAAW,SAAS,CAAC;CAClC,MAAM,CAAC,UAAU,eAAe,SAAS,CAAC;CAC1C,MAAM,CAAC,OAAO,YAAY,SAAS,CAAC;CACpC,MAAM,CAAC,YAAY,iBAAiB,SAAS,IAAI;CACjD,MAAM,SAAS,OAAgC,IAAI;CACnD,MAAM,eAAe,OAAuB,IAAI;CAChD,MAAM,YAAY,OAA0B,IAAI;CAKhD,gBAAgB;EACd,IAAI,YAAY;EAChB,IAAI,cAAqC;EACzC,OAAO,UAAU;EACjB,QAAQ,CAAC;EACT,YAAY,CAAC;EACb,cAAc,IAAI;EAClB,SAAS,CAAC;EAEV,IAAI,CAAC,KAAK;GACR,UAAU,OAAO;GACjB;EACF;EACA,MAAM,YAAoB;EAE1B,UAAU,SAAS;EACnB,eAAe,OAAO;GACpB,IAAI;IACF,MAAM,CAAC,UAAU,gBAAgB,MAAM,QAAQ,IAAI,CACjD,OAAO,eACP,OAAO,0CACT,CAAC;IACD,SAAS,oBAAoB,YAAY,aAAa;IACtD,IAAI,WAAW;IACf,cAAc,SAAS,YAAY,EAAE,KAAK,UAAU,CAAC;IACrD,MAAM,MAAM,MAAM,YAAY;IAC9B,IAAI,WAAW;IACf,OAAO,UAAU;IACjB,YAAY,IAAI,QAAQ;IACxB,UAAU,OAAO;GACnB,QAAQ;IACN,IAAI,WAAW;IACf,UAAU,OAAO;GACnB;EACF;EACA,KAAU;EACV,aAAa;GACX,YAAY;GACZ,aAAkB,QAAQ;EAC5B;CACF,GAAG,CAAC,GAAG,CAAC;CAGR,gBAAgB;EACd,IAAI,WAAW,WAAW,CAAC,OAAO,SAAS;EAC3C,IAAI,YAAY;EAChB,eAAe,OAAO;GACpB,MAAM,MAAM,OAAO;GACnB,IAAI,CAAC,KAAK;GACV,MAAM,UAAU,MAAM,IAAI,QAAQ,IAAI;GACtC,IAAI,WAAW;GACf,MAAM,UAAU,QAAQ,YAAY,EAAE,OAAO,EAAE,CAAC;GAChD,MAAM,iBAAiB,aAAa,SAAS,eAAe;GAC5D,MAAM,iBACJ,cAAc,iBAAiB,IAAI,iBAAiB,QAAQ,QAAQ;GACtE,MAAM,WAAW,QAAQ,YAAY,EAAE,OAAO,eAAe,CAAC;GAC9D,MAAM,SAAS,UAAU;GACzB,IAAI,CAAC,QAAQ;GACb,OAAO,QAAQ,SAAS;GACxB,OAAO,SAAS,SAAS;GACzB,MAAM,MAAM,OAAO,WAAW,IAAI;GAGlC,IAAI,CAAC,KAAK;GACV,MAAM,QAAQ,OAAO;IAAE;IAAQ,eAAe;IAAK;GAAS,CAAC,CAAC,CAAC;EACjE;EACA,KAAU;EACV,aAAa;GACX,YAAY;EACd;CACF,GAAG;EAAC;EAAQ;EAAM;EAAO;CAAU,CAAC;CAEpC,MAAM,eAAe;EACnB,cAAc,KAAK;EACnB,UAAU,MAAM,KAAK,IAAI,WAAW,IAAI,SAAS,CAAC;CACpD;CACA,MAAM,gBAAgB;EACpB,cAAc,KAAK;EACnB,UAAU,MAAM,KAAK,IAAI,WAAW,IAAI,SAAS,CAAC;CACpD;CAEA,OACE,qBAAC,OAAD;EACE,eAAY;EACZ,MAAK;EACL,cAAY;EACZ,WAAW,GACT,iFACA,SACF;EAPF,UAAA;GASG,WAAW,WACV,oBAAC,YAAD;IAAY,OAAO;IAAY,aAAa;IAAkB,WAAU;GAAU,CAAA;GAGnF,WAAW,aACV,oBAAC,OAAD;IACE,WAAU;IACV,MAAK;IAEJ,UAAA;GACE,CAAA;GAGN,WAAW,WACV,oBAAC,YAAD;IACE,MAAK;IACL,OAAO;IACP,aAAa;IACb,WAAU;IACV,SACE,OACE,oBAAC,QAAD;KAAQ,SAAQ;KAAU,SAAA;KACxB,UAAA,qBAAC,KAAD;MAAG,MAAM;MAAK,QAAO;MAAS,KAAI;MAAlC,UAAA,CACE,oBAAC,cAAD,EAAc,eAAA,KAAa,CAAA,GAC1B,iBACA;;IACG,CAAA;GAGb,CAAA;GAGF,WAAW,WACV,qBAAA,UAAA,EAAA,UAAA,CACE,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACE,oBAAC,QAAD;OACE,SAAQ;OACR,MAAK;OACL,UAAA;OACA,cAAY;OACZ,MAAM,oBAAC,SAAD,CAAU,CAAA;OAChB,SAAS;MACV,CAAA;MACD,oBAAC,QAAD;OAAM,WAAU;OACb,UAAA,aAAa,YAAY,GAAG,KAAK,MAAM,QAAQ,GAAG,EAAE;MACjD,CAAA;MACN,oBAAC,QAAD;OACE,SAAQ;OACR,MAAK;OACL,UAAA;OACA,cAAY;OACZ,MAAM,oBAAC,QAAD,CAAS,CAAA;OACf,SAAS;MACV,CAAA;KACE;IACJ,CAAA,GAAA,WAAW,KACV,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACE,oBAAC,QAAD;OACE,SAAQ;OACR,MAAK;OACL,UAAA;OACA,cAAY;OACZ,MAAM,oBAAC,aAAD,CAAc,CAAA;OACpB,UAAU,QAAQ;OAClB,eAAe,SAAS,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;MACjD,CAAA;MACD,qBAAC,QAAD;OAAM,WAAU;OAA6C,aAAU;OAAvE,UAAA;QACG;QAAK;QAAK;OACP;;MACN,oBAAC,QAAD;OACE,SAAQ;OACR,MAAK;OACL,UAAA;OACA,cAAY;OACZ,MAAM,oBAAC,cAAD,CAAe,CAAA;OACrB,UAAU,QAAQ;OAClB,eAAe,SAAS,MAAM,KAAK,IAAI,UAAU,IAAI,CAAC,CAAC;MACxD,CAAA;KACE;IAEJ,CAAA,CAAA;GACL,CAAA,GAAA,oBAAC,OAAD;IACE,KAAK;IACL,WAAU;IAEV,UAAA,oBAAC,UAAD;KAAQ,KAAK;KAAW,WAAU;IAA6C,CAAA;GAC5E,CAAA,CACL,EAAA,CAAA;EAED;;AAET"}
1
+ {"version":3,"file":"document-viewer.js","names":[],"sources":["../src/components/ui/document-viewer.tsx"],"sourcesContent":["import { ChevronLeft, ChevronRight, ExternalLink, ZoomIn, ZoomOut } from 'lucide-react'\nimport { useEffect, useRef, useState } from 'react'\nimport { Button } from '@/components/ui/button'\nimport { EmptyState } from '@/components/ui/empty-state'\nimport { cn } from '@/lib/cn'\n\n/*\n * Visualizador de documentos PDF. Carrega o pdfjs-dist sob demanda (import dinâmico), com o\n * worker também sob demanda, para o pacote principal nunca pagar o custo de quem não usa o\n * visualizador. url null é o estado vazio legítimo (nenhum documento escolhido ainda). Falha\n * (CORS, arquivo inválido) é declarada, nunca uma tela em branco: sempre com o link \"Abrir em\n * nova aba\".\n */\n\n// pdfjs-dist é grande e só entra no bundle de quem realmente usa o DocumentViewer: os tipos\n// abaixo são só de compilação (import de tipo), o import de valor é sempre dinâmico (import()).\ntype PdfDocumentProxy = import('pdfjs-dist').PDFDocumentProxy\n// destroy() vive na tarefa de carregamento (o que getDocument devolve antes do .promise),\n// não no documento já resolvido: é ela que precisa ser guardada para liberar depois.\ntype PdfLoadingTask = import('pdfjs-dist').PDFDocumentLoadingTask\n\ntype Status = 'empty' | 'loading' | 'ready' | 'error'\n\nexport interface DocumentViewerProps {\n /** Endereço do PDF. null é o estado vazio legítimo (nenhum documento escolhido ainda). */\n url: string | null\n /** Nome acessível do documento (aria-label do visualizador). */\n title: string\n className?: string\n emptyTitle?: string\n emptyDescription?: string\n loadingLabel?: string\n errorTitle?: string\n errorDescription?: string\n openInNewTabLabel?: string\n zoomInLabel?: string\n zoomOutLabel?: string\n previousPageLabel?: string\n nextPageLabel?: string\n}\n\nconst MIN_SCALE = 0.25\nconst MAX_SCALE = 3\nconst ZOOM_STEP = 1.25\n\n/** Um visualizador de documento por tela; nunca crie um segundo para PDF. */\nexport function DocumentViewer({\n url,\n title,\n className,\n emptyTitle = 'Nenhum documento selecionado',\n emptyDescription = 'Escolha um arquivo PDF para visualizar aqui.',\n loadingLabel = 'Carregando documento...',\n errorTitle = 'Não foi possível abrir o documento',\n errorDescription = 'O arquivo pode estar indisponível, corrompido ou bloqueado por CORS.',\n openInNewTabLabel = 'Abrir em nova aba',\n zoomInLabel = 'Aumentar zoom',\n zoomOutLabel = 'Diminuir zoom',\n previousPageLabel = 'Página anterior',\n nextPageLabel = 'Próxima página',\n}: DocumentViewerProps) {\n const [status, setStatus] = useState<Status>(url ? 'loading' : 'empty')\n const [page, setPage] = useState(1)\n const [numPages, setNumPages] = useState(0)\n const [scale, setScale] = useState(1)\n const [fitToWidth, setFitToWidth] = useState(true)\n const pdfRef = useRef<PdfDocumentProxy | null>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n const canvasRef = useRef<HTMLCanvasElement>(null)\n\n // Carrega o documento (ou reinicia o estado vazio) sempre que a url muda. Libera a tarefa\n // de carregamento (destroy) ao trocar de url e ao desmontar, para não vazar memória nem o\n // worker que o pdfjs sobe para cada documento.\n useEffect(() => {\n let cancelled = false\n let loadingTask: PdfLoadingTask | null = null\n pdfRef.current = null\n setPage(1)\n setNumPages(0)\n setFitToWidth(true)\n setScale(1)\n\n if (!url) {\n setStatus('empty')\n return\n }\n const targetUrl: string = url\n\n setStatus('loading')\n async function load() {\n try {\n const [pdfjsLib, workerModule] = await Promise.all([\n import('pdfjs-dist'),\n import('pdfjs-dist/build/pdf.worker.min.mjs?url'),\n ])\n pdfjsLib.GlobalWorkerOptions.workerSrc = workerModule.default\n if (cancelled) return\n loadingTask = pdfjsLib.getDocument({ url: targetUrl })\n const doc = await loadingTask.promise\n if (cancelled) return\n pdfRef.current = doc\n setNumPages(doc.numPages)\n setStatus('ready')\n } catch {\n if (cancelled) return\n setStatus('error')\n }\n }\n void load()\n return () => {\n cancelled = true\n void loadingTask?.destroy()\n }\n }, [url])\n\n // Desenha a página atual sempre que ela, o zoom ou o modo \"ajustar à largura\" mudam.\n useEffect(() => {\n if (status !== 'ready' || !pdfRef.current) return\n let cancelled = false\n async function draw() {\n const doc = pdfRef.current\n if (!doc) return\n const pdfPage = await doc.getPage(page)\n if (cancelled) return\n const natural = pdfPage.getViewport({ scale: 1 })\n const containerWidth = containerRef.current?.clientWidth ?? 0\n const effectiveScale =\n fitToWidth && containerWidth > 0 ? containerWidth / natural.width : scale\n const viewport = pdfPage.getViewport({ scale: effectiveScale })\n const canvas = canvasRef.current\n if (!canvas) return\n canvas.width = viewport.width\n canvas.height = viewport.height\n const ctx = canvas.getContext('2d')\n // Sem contexto 2D disponível (ambiente sem canvas real): mantém os controles\n // funcionando, só não desenha o pixel a pixel.\n if (!ctx) return\n await pdfPage.render({ canvas, canvasContext: ctx, viewport }).promise\n }\n void draw()\n return () => {\n cancelled = true\n }\n }, [status, page, scale, fitToWidth])\n\n const zoomIn = () => {\n setFitToWidth(false)\n setScale((s) => Math.min(MAX_SCALE, s * ZOOM_STEP))\n }\n const zoomOut = () => {\n setFitToWidth(false)\n setScale((s) => Math.max(MIN_SCALE, s / ZOOM_STEP))\n }\n\n return (\n <div\n data-rendra=\"DOC-001\"\n role=\"group\"\n aria-label={title}\n className={cn(\n 'flex h-viewer min-h-0 flex-col overflow-hidden rounded-surface border bg-card',\n className,\n )}\n >\n {status === 'empty' && (\n <EmptyState title={emptyTitle} description={emptyDescription} className=\"m-auto\" />\n )}\n\n {status === 'loading' && (\n <div\n className=\"m-auto flex flex-col items-center gap-2 px-4 py-8 text-sm text-muted-foreground\"\n role=\"status\"\n >\n {loadingLabel}\n </div>\n )}\n\n {status === 'error' && (\n <EmptyState\n type=\"error\"\n title={errorTitle}\n description={errorDescription}\n className=\"m-auto\"\n actions={\n url && (\n <Button variant=\"outline\" asChild>\n <a href={url} target=\"_blank\" rel=\"noreferrer\">\n <ExternalLink aria-hidden />\n {openInNewTabLabel}\n </a>\n </Button>\n )\n }\n />\n )}\n\n {status === 'ready' && (\n <>\n <div className=\"flex shrink-0 items-center justify-between gap-3 border-b bg-card px-3 py-2\">\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n aria-label={zoomOutLabel}\n icon={<ZoomOut />}\n onClick={zoomOut}\n />\n <span className=\"w-12 text-center text-xs text-muted-foreground tabular-nums\">\n {fitToWidth ? 'Ajustar' : `${Math.round(scale * 100)}%`}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n aria-label={zoomInLabel}\n icon={<ZoomIn />}\n onClick={zoomIn}\n />\n </div>\n {numPages > 1 && (\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n aria-label={previousPageLabel}\n icon={<ChevronLeft />}\n disabled={page <= 1}\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n />\n <span className=\"text-xs text-muted-foreground tabular-nums\" aria-live=\"polite\">\n {page} de {numPages}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n aria-label={nextPageLabel}\n icon={<ChevronRight />}\n disabled={page >= numPages}\n onClick={() => setPage((p) => Math.min(numPages, p + 1))}\n />\n </div>\n )}\n </div>\n <div\n ref={containerRef}\n className=\"flex min-h-0 flex-1 items-center justify-center overflow-auto bg-muted p-4\"\n >\n <canvas ref={canvasRef} className=\"max-w-full rounded-item bg-card shadow-sm\" />\n </div>\n </>\n )}\n </div>\n )\n}\n"],"mappings":"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"}