trama-ui 0.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 (285) hide show
  1. package/CATALOG.md +1237 -0
  2. package/LICENSE +21 -0
  3. package/README.md +78 -0
  4. package/THIRD-PARTY.md +4 -0
  5. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/brown.png +0 -0
  6. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/brown_inlay.png +0 -0
  7. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/brown_pressed.png +0 -0
  8. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/grey.png +0 -0
  9. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/grey_inlay.png +0 -0
  10. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/grey_pressed.png +0 -0
  11. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/tan.png +0 -0
  12. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/tan_inlay.png +0 -0
  13. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/tan_pressed.png +0 -0
  14. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/white.png +0 -0
  15. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/white_inlay.png +0 -0
  16. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/white_pressed.png +0 -0
  17. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/blue.png +0 -0
  18. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/blue_pressed.png +0 -0
  19. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/green.png +0 -0
  20. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/green_pressed.png +0 -0
  21. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/grey.png +0 -0
  22. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/grey_pressed.png +0 -0
  23. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/red.png +0 -0
  24. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/red_pressed.png +0 -0
  25. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/yellow.png +0 -0
  26. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/yellow_pressed.png +0 -0
  27. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/blue.png +0 -0
  28. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/blue_pressed.png +0 -0
  29. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/green.png +0 -0
  30. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/green_pressed.png +0 -0
  31. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/red.png +0 -0
  32. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/red_pressed.png +0 -0
  33. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/yellow.png +0 -0
  34. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/yellow_pressed.png +0 -0
  35. package/assets/pixel/kenney-pixel-ui/9-slice/list.png +0 -0
  36. package/assets/pixel/kenney-pixel-ui/9-slice/space.png +0 -0
  37. package/assets/pixel/kenney-pixel-ui/9-slice/space_inlay.png +0 -0
  38. package/assets/pixel/kenney-pixel-ui/License.txt +23 -0
  39. package/assets/pixel/kenney-pixel-ui/spritesheet/sheet.png +0 -0
  40. package/bin/trama-ui.mjs +27 -0
  41. package/dist/components/ui/Accordion.d.ts +12 -0
  42. package/dist/components/ui/Accordion.js +12 -0
  43. package/dist/components/ui/Alert.d.ts +15 -0
  44. package/dist/components/ui/Alert.js +15 -0
  45. package/dist/components/ui/ArticlesSection.d.ts +30 -0
  46. package/dist/components/ui/ArticlesSection.js +18 -0
  47. package/dist/components/ui/AsciiBackground.d.ts +58 -0
  48. package/dist/components/ui/AsciiBackground.js +173 -0
  49. package/dist/components/ui/AsciiCard.d.ts +78 -0
  50. package/dist/components/ui/AsciiCard.js +253 -0
  51. package/dist/components/ui/AsciiChart.d.ts +18 -0
  52. package/dist/components/ui/AsciiChart.js +47 -0
  53. package/dist/components/ui/Badge.d.ts +15 -0
  54. package/dist/components/ui/Badge.js +8 -0
  55. package/dist/components/ui/BitmapText.d.ts +25 -0
  56. package/dist/components/ui/BitmapText.js +21 -0
  57. package/dist/components/ui/BlogCard.d.ts +33 -0
  58. package/dist/components/ui/BlogCard.js +13 -0
  59. package/dist/components/ui/Breadcrumbs.d.ts +9 -0
  60. package/dist/components/ui/Breadcrumbs.js +7 -0
  61. package/dist/components/ui/Button.d.ts +74 -0
  62. package/dist/components/ui/Button.js +48 -0
  63. package/dist/components/ui/CTASection.d.ts +13 -0
  64. package/dist/components/ui/CTASection.js +7 -0
  65. package/dist/components/ui/Carousel.d.ts +30 -0
  66. package/dist/components/ui/Carousel.js +80 -0
  67. package/dist/components/ui/CheckboxGroup.d.ts +11 -0
  68. package/dist/components/ui/CheckboxGroup.js +20 -0
  69. package/dist/components/ui/CodeBlock.d.ts +11 -0
  70. package/dist/components/ui/CodeBlock.js +20 -0
  71. package/dist/components/ui/ContactForm.d.ts +25 -0
  72. package/dist/components/ui/ContactForm.js +26 -0
  73. package/dist/components/ui/CrtOverlay.d.ts +10 -0
  74. package/dist/components/ui/CrtOverlay.js +5 -0
  75. package/dist/components/ui/Divider.d.ts +12 -0
  76. package/dist/components/ui/Divider.js +7 -0
  77. package/dist/components/ui/Drawer.d.ts +16 -0
  78. package/dist/components/ui/Drawer.js +25 -0
  79. package/dist/components/ui/Dropdown.d.ts +10 -0
  80. package/dist/components/ui/Dropdown.js +21 -0
  81. package/dist/components/ui/FAQSection.d.ts +14 -0
  82. package/dist/components/ui/FAQSection.js +7 -0
  83. package/dist/components/ui/FeatureGrid.d.ts +18 -0
  84. package/dist/components/ui/FeatureGrid.js +14 -0
  85. package/dist/components/ui/Footer.d.ts +14 -0
  86. package/dist/components/ui/Footer.js +16 -0
  87. package/dist/components/ui/GlyphCursor.d.ts +22 -0
  88. package/dist/components/ui/GlyphCursor.js +50 -0
  89. package/dist/components/ui/GridBackground.d.ts +15 -0
  90. package/dist/components/ui/GridBackground.js +6 -0
  91. package/dist/components/ui/Hero.d.ts +21 -0
  92. package/dist/components/ui/Hero.js +12 -0
  93. package/dist/components/ui/HoverFX.d.ts +29 -0
  94. package/dist/components/ui/HoverFX.js +75 -0
  95. package/dist/components/ui/Icon.d.ts +33 -0
  96. package/dist/components/ui/Icon.js +29 -0
  97. package/dist/components/ui/ImageGallery.d.ts +31 -0
  98. package/dist/components/ui/ImageGallery.js +79 -0
  99. package/dist/components/ui/LogoCloud.d.ts +12 -0
  100. package/dist/components/ui/LogoCloud.js +9 -0
  101. package/dist/components/ui/MagneticButton.d.ts +12 -0
  102. package/dist/components/ui/MagneticButton.js +49 -0
  103. package/dist/components/ui/Marquee.d.ts +29 -0
  104. package/dist/components/ui/Marquee.js +15 -0
  105. package/dist/components/ui/Modal.d.ts +40 -0
  106. package/dist/components/ui/Modal.js +51 -0
  107. package/dist/components/ui/NavBar.d.ts +14 -0
  108. package/dist/components/ui/NavBar.js +12 -0
  109. package/dist/components/ui/NeonSign.d.ts +14 -0
  110. package/dist/components/ui/NeonSign.js +7 -0
  111. package/dist/components/ui/OtpInput.d.ts +9 -0
  112. package/dist/components/ui/OtpInput.js +27 -0
  113. package/dist/components/ui/Pagination.d.ts +10 -0
  114. package/dist/components/ui/Pagination.js +24 -0
  115. package/dist/components/ui/Panel.d.ts +21 -0
  116. package/dist/components/ui/Panel.js +8 -0
  117. package/dist/components/ui/PixelFrame.d.ts +61 -0
  118. package/dist/components/ui/PixelFrame.js +29 -0
  119. package/dist/components/ui/Presence.d.ts +51 -0
  120. package/dist/components/ui/Presence.js +343 -0
  121. package/dist/components/ui/PricingCard.d.ts +30 -0
  122. package/dist/components/ui/PricingCard.js +21 -0
  123. package/dist/components/ui/PricingSection.d.ts +35 -0
  124. package/dist/components/ui/PricingSection.js +21 -0
  125. package/dist/components/ui/Progress.d.ts +17 -0
  126. package/dist/components/ui/Progress.js +9 -0
  127. package/dist/components/ui/RadioGroup.d.ts +10 -0
  128. package/dist/components/ui/RadioGroup.js +11 -0
  129. package/dist/components/ui/RangeSlider.d.ts +14 -0
  130. package/dist/components/ui/RangeSlider.js +11 -0
  131. package/dist/components/ui/Reveal.d.ts +48 -0
  132. package/dist/components/ui/Reveal.js +181 -0
  133. package/dist/components/ui/SceneFlash.d.ts +14 -0
  134. package/dist/components/ui/SceneFlash.js +51 -0
  135. package/dist/components/ui/ScrambleText.d.ts +31 -0
  136. package/dist/components/ui/ScrambleText.js +51 -0
  137. package/dist/components/ui/ScrollArea.d.ts +15 -0
  138. package/dist/components/ui/ScrollArea.js +18 -0
  139. package/dist/components/ui/SectionHeader.d.ts +12 -0
  140. package/dist/components/ui/SectionHeader.js +6 -0
  141. package/dist/components/ui/Select.d.ts +17 -0
  142. package/dist/components/ui/Select.js +31 -0
  143. package/dist/components/ui/Skeleton.d.ts +12 -0
  144. package/dist/components/ui/Skeleton.js +18 -0
  145. package/dist/components/ui/Spinner.d.ts +15 -0
  146. package/dist/components/ui/Spinner.js +24 -0
  147. package/dist/components/ui/Spotlight.d.ts +16 -0
  148. package/dist/components/ui/Spotlight.js +16 -0
  149. package/dist/components/ui/Sprite.d.ts +27 -0
  150. package/dist/components/ui/Sprite.js +19 -0
  151. package/dist/components/ui/StatCounter.d.ts +24 -0
  152. package/dist/components/ui/StatCounter.js +70 -0
  153. package/dist/components/ui/StatsSection.d.ts +14 -0
  154. package/dist/components/ui/StatsSection.js +13 -0
  155. package/dist/components/ui/Stepper.d.ts +10 -0
  156. package/dist/components/ui/Stepper.js +7 -0
  157. package/dist/components/ui/Table.d.ts +10 -0
  158. package/dist/components/ui/Table.js +8 -0
  159. package/dist/components/ui/Tabs.d.ts +12 -0
  160. package/dist/components/ui/Tabs.js +18 -0
  161. package/dist/components/ui/TeamSection.d.ts +18 -0
  162. package/dist/components/ui/TeamSection.js +19 -0
  163. package/dist/components/ui/TerminalTyper.d.ts +20 -0
  164. package/dist/components/ui/TerminalTyper.js +45 -0
  165. package/dist/components/ui/Testimonial.d.ts +19 -0
  166. package/dist/components/ui/Testimonial.js +9 -0
  167. package/dist/components/ui/TestimonialSection.d.ts +20 -0
  168. package/dist/components/ui/TestimonialSection.js +15 -0
  169. package/dist/components/ui/TextField.d.ts +26 -0
  170. package/dist/components/ui/TextField.js +13 -0
  171. package/dist/components/ui/TextmodeBackground.d.ts +52 -0
  172. package/dist/components/ui/TextmodeBackground.js +83 -0
  173. package/dist/components/ui/Timeline.d.ts +13 -0
  174. package/dist/components/ui/Timeline.js +8 -0
  175. package/dist/components/ui/Toast.d.ts +30 -0
  176. package/dist/components/ui/Toast.js +47 -0
  177. package/dist/components/ui/Toggle.d.ts +13 -0
  178. package/dist/components/ui/Toggle.js +10 -0
  179. package/dist/components/ui/Tooltip.d.ts +20 -0
  180. package/dist/components/ui/Tooltip.js +20 -0
  181. package/dist/components/ui/Typewriter.d.ts +20 -0
  182. package/dist/components/ui/Typewriter.js +46 -0
  183. package/dist/components/ui/VideoPlayer.d.ts +81 -0
  184. package/dist/components/ui/VideoPlayer.js +379 -0
  185. package/dist/components/ui/fill.d.ts +32 -0
  186. package/dist/components/ui/fill.js +27 -0
  187. package/dist/components/ui/intent.d.ts +20 -0
  188. package/dist/components/ui/intent.js +23 -0
  189. package/dist/components/ui/styles/kit.css +31 -0
  190. package/dist/components/ui/styles/ui-carousel.css +113 -0
  191. package/dist/components/ui/styles/ui-kit.css +1135 -0
  192. package/dist/components/ui/styles/ui-video.css +75 -0
  193. package/dist/components/ui/swiperCss.d.ts +15 -0
  194. package/dist/components/ui/swiperCss.js +15 -0
  195. package/dist/components/ui/variants.d.ts +12 -0
  196. package/dist/components/ui/variants.js +10 -0
  197. package/dist/index.d.ts +77 -0
  198. package/dist/index.js +77 -0
  199. package/dist/lib/asciify/painters.d.ts +25 -0
  200. package/dist/lib/asciify/painters.js +604 -0
  201. package/dist/lib/asciify/pointer.d.ts +12 -0
  202. package/dist/lib/asciify/pointer.js +54 -0
  203. package/dist/lib/asciify/shape-painters.d.ts +44 -0
  204. package/dist/lib/asciify/shape-painters.js +335 -0
  205. package/dist/lib/asciify/theme-painters.d.ts +8 -0
  206. package/dist/lib/asciify/theme-painters.js +437 -0
  207. package/dist/lib/cells.d.ts +46 -0
  208. package/dist/lib/cells.js +114 -0
  209. package/dist/lib/scroll/store.d.ts +21 -0
  210. package/dist/lib/scroll/store.js +25 -0
  211. package/dist/lib/sketches/aurora.d.ts +3 -0
  212. package/dist/lib/sketches/aurora.js +42 -0
  213. package/dist/lib/sketches/fire.d.ts +3 -0
  214. package/dist/lib/sketches/fire.js +80 -0
  215. package/dist/lib/sketches/flow.d.ts +3 -0
  216. package/dist/lib/sketches/flow.js +70 -0
  217. package/dist/lib/sketches/life.d.ts +3 -0
  218. package/dist/lib/sketches/life.js +107 -0
  219. package/dist/lib/sketches/matrix.d.ts +3 -0
  220. package/dist/lib/sketches/matrix.js +64 -0
  221. package/dist/lib/sketches/ocean.d.ts +3 -0
  222. package/dist/lib/sketches/ocean.js +56 -0
  223. package/dist/lib/sketches/plasma.d.ts +3 -0
  224. package/dist/lib/sketches/plasma.js +29 -0
  225. package/dist/lib/sketches/registry.d.ts +6 -0
  226. package/dist/lib/sketches/registry.js +60 -0
  227. package/dist/lib/sketches/ripples.d.ts +3 -0
  228. package/dist/lib/sketches/ripples.js +84 -0
  229. package/dist/lib/sketches/scroll-assemble.d.ts +8 -0
  230. package/dist/lib/sketches/scroll-assemble.js +90 -0
  231. package/dist/lib/sketches/scroll-parallax.d.ts +6 -0
  232. package/dist/lib/sketches/scroll-parallax.js +76 -0
  233. package/dist/lib/sketches/scroll-rain.d.ts +6 -0
  234. package/dist/lib/sketches/scroll-rain.js +82 -0
  235. package/dist/lib/sketches/scroll-stats.d.ts +7 -0
  236. package/dist/lib/sketches/scroll-stats.js +81 -0
  237. package/dist/lib/sketches/scroll-terminal.d.ts +6 -0
  238. package/dist/lib/sketches/scroll-terminal.js +87 -0
  239. package/dist/lib/sketches/scroll-zoom.d.ts +7 -0
  240. package/dist/lib/sketches/scroll-zoom.js +49 -0
  241. package/dist/lib/sketches/starfield.d.ts +3 -0
  242. package/dist/lib/sketches/starfield.js +54 -0
  243. package/dist/lib/sketches/text-3d.d.ts +6 -0
  244. package/dist/lib/sketches/text-3d.js +62 -0
  245. package/dist/lib/sketches/text-combo-figlet.d.ts +6 -0
  246. package/dist/lib/sketches/text-combo-figlet.js +91 -0
  247. package/dist/lib/sketches/text-glitch.d.ts +3 -0
  248. package/dist/lib/sketches/text-glitch.js +57 -0
  249. package/dist/lib/sketches/text-marquee.d.ts +3 -0
  250. package/dist/lib/sketches/text-marquee.js +35 -0
  251. package/dist/lib/sketches/text-particles.d.ts +9 -0
  252. package/dist/lib/sketches/text-particles.js +91 -0
  253. package/dist/lib/sketches/text-rain.d.ts +3 -0
  254. package/dist/lib/sketches/text-rain.js +73 -0
  255. package/dist/lib/sketches/text-scramble.d.ts +6 -0
  256. package/dist/lib/sketches/text-scramble.js +49 -0
  257. package/dist/lib/sketches/text-wave.d.ts +3 -0
  258. package/dist/lib/sketches/text-wave.js +43 -0
  259. package/dist/lib/sketches/theme-orbit.d.ts +6 -0
  260. package/dist/lib/sketches/theme-orbit.js +119 -0
  261. package/dist/lib/sketches/theme-pulse.d.ts +7 -0
  262. package/dist/lib/sketches/theme-pulse.js +84 -0
  263. package/dist/lib/sketches/tunnel.d.ts +3 -0
  264. package/dist/lib/sketches/tunnel.js +28 -0
  265. package/dist/lib/text/banner.d.ts +5 -0
  266. package/dist/lib/text/banner.js +35 -0
  267. package/dist/lib/text/mask.d.ts +40 -0
  268. package/dist/lib/text/mask.js +143 -0
  269. package/dist/lib/text/store.d.ts +23 -0
  270. package/dist/lib/text/store.js +86 -0
  271. package/dist/lib/ui/card-fields.d.ts +52 -0
  272. package/dist/lib/ui/card-fields.js +193 -0
  273. package/dist/lib/ui/fonts.d.ts +56 -0
  274. package/dist/lib/ui/fonts.js +94 -0
  275. package/dist/lib/ui/fx.d.ts +42 -0
  276. package/dist/lib/ui/fx.js +162 -0
  277. package/dist/lib/ui/icons.d.ts +437 -0
  278. package/dist/lib/ui/icons.js +314 -0
  279. package/dist/lib/ui/placeholder.d.ts +11 -0
  280. package/dist/lib/ui/placeholder.js +65 -0
  281. package/dist/lib/ui/tokens.d.ts +49 -0
  282. package/dist/lib/ui/tokens.js +129 -0
  283. package/dist/lib/ui/useTokens.d.ts +10 -0
  284. package/dist/lib/ui/useTokens.js +32 -0
  285. package/package.json +80 -0
@@ -0,0 +1,78 @@
1
+ import type { SourceKind } from "../../lib/asciify/painters.js";
2
+ import { type CardCharset, type CardField, type CardFieldColor, type CardFieldHover } from "../../lib/ui/card-fields.js";
3
+ import { type ASCII_STYLES } from "./AsciiBackground.js";
4
+ import { type CardFill, type CardPattern, type CardTone } from "./fill.js";
5
+ import { type Variant } from "./variants.js";
6
+ export type HoverFx = "spotlight" | "magnify" | "repel" | "glow" | "colorShift" | "attract" | "shatter" | "trail" | "glitchText";
7
+ export type AsciiCardProps = {
8
+ title: string;
9
+ text: string;
10
+ meta?: string;
11
+ /** número que se dibuja en ASCII (01, 02…) */
12
+ index?: number;
13
+ showNumeral?: boolean;
14
+ /** carácter con el que se dibuja el número y las esquinas */
15
+ glyph?: string;
16
+ /**
17
+ * capa ASCII del fondo:
18
+ * - `field`: campo de caracteres procedural (`field`, `charset`, `fieldColor`, `fieldHover`), ligero y animado
19
+ * - `text`: el texto `tile` repetido, con hover de asciify-engine (`hover`)
20
+ * - `scene`: una escena de `AsciiBackground` (`scene`, `sceneStyle`); la más vistosa y la más pesada
21
+ * - `none`: sin capa (solo el `fill`)
22
+ */
23
+ background?: "field" | "text" | "scene" | "none";
24
+ field?: CardField;
25
+ charset?: CardCharset;
26
+ fieldColor?: CardFieldColor;
27
+ fieldHover?: CardFieldHover;
28
+ /** anima el campo (se pausa fuera de pantalla y con movimiento reducido) */
29
+ animate?: boolean;
30
+ /** velocidad de la animación del campo */
31
+ speed?: number;
32
+ scene?: SourceKind;
33
+ sceneStyle?: (typeof ASCII_STYLES)[number];
34
+ /** patrón de texto que se repite como fondo con `background="text"` */
35
+ tile?: string;
36
+ /** tamaño de celda / fuente de la capa ASCII en px */
37
+ tileSize?: number;
38
+ /** opacidad de la capa ASCII (10–255) */
39
+ tileOpacity?: number;
40
+ /** efecto de hover de asciify-engine con background="text" */
41
+ textHover?: HoverFx;
42
+ /** @deprecated usa `textHover` */
43
+ hover?: HoverFx;
44
+ hoverStrength?: number;
45
+ hoverRadius?: number;
46
+ variant?: Variant;
47
+ /** fondo de la tarjeta: surface · tint · gradient · accent (invertida) · pattern · image (ver fill.ts) */
48
+ fill?: CardFill;
49
+ pattern?: CardPattern;
50
+ tone?: CardTone;
51
+ /** con fill="image": URL/ruta o `gen:N` */
52
+ image?: string;
53
+ reveal?: "none" | "wipe" | "rise" | "dissolve";
54
+ revealDuration?: number;
55
+ /** tamaño de las celdas de la disolución en px */
56
+ dissolveCell?: number;
57
+ /** cuándo se revela: al montar o al entrar en pantalla */
58
+ trigger?: "mount" | "inview";
59
+ tilt?: boolean;
60
+ /** inclinación máxima en grados */
61
+ tiltMax?: number;
62
+ scramble?: boolean;
63
+ chars?: string;
64
+ /** brillo que sigue al ratón */
65
+ glow?: boolean;
66
+ align?: "left" | "center";
67
+ minHeight?: number;
68
+ /** cambia el número para repetir el revelado desde fuera */
69
+ playKey?: number;
70
+ className?: string;
71
+ };
72
+ /**
73
+ * Tarjeta con tres capas de ASCII: el número en fuente bitmap, un fondo ASCII (campo procedural, texto repetido o
74
+ * escena de AsciiBackground, ver `background`) y un revelado por disolución. Además: inclinación hacia el puntero, brillo que
75
+ * sigue al ratón y título que se descifra. Todo el color sale de los tokens `--bg --mut --acc --acc2`
76
+ * y se actualiza al cambiar de tema sin repetir el revelado.
77
+ */
78
+ export default function AsciiCard({ title, text, meta, index, showNumeral, glyph, background, field, charset, fieldColor, fieldHover, animate, speed, scene, sceneStyle, tile, tileSize, tileOpacity, textHover, hover: legacyHover, hoverStrength, hoverRadius, variant, fill, pattern, tone, image, reveal, revealDuration, dissolveCell, trigger, tilt, tiltMax, scramble, chars, glow, align, minHeight, playKey, className, }: AsciiCardProps): import("react").JSX.Element;
@@ -0,0 +1,253 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useRef } from "react";
4
+ import { ANIMATED_FIELDS, drawCardField } from "../../lib/ui/card-fields.js";
5
+ import { token } from "../../lib/ui/tokens.js";
6
+ import { useTokens } from "../../lib/ui/useTokens.js";
7
+ import AsciiBackground from "./AsciiBackground.js";
8
+ import { fillProps } from "./fill.js";
9
+ import { vcls } from "./variants.js";
10
+ const hash = (n) => {
11
+ const x = Math.sin(n * 127.1 + 311.7) * 43758.5453;
12
+ return x - Math.floor(x);
13
+ };
14
+ /**
15
+ * Tarjeta con tres capas de ASCII: el número en fuente bitmap, un fondo ASCII (campo procedural, texto repetido o
16
+ * escena de AsciiBackground, ver `background`) y un revelado por disolución. Además: inclinación hacia el puntero, brillo que
17
+ * sigue al ratón y título que se descifra. Todo el color sale de los tokens `--bg --mut --acc --acc2`
18
+ * y se actualiza al cambiar de tema sin repetir el revelado.
19
+ */
20
+ export default function AsciiCard({ title, text, meta, index = 1, showNumeral = true, glyph = "#", background = "field", field = "plasma", charset = "detailed", fieldColor = "mut", fieldHover = "glow", animate = true, speed = 1, scene = "waves", sceneStyle = "braille", tile = "OLA · MAR · SAL · ", tileSize = 11, tileOpacity = 110, textHover, hover: legacyHover, hoverStrength = 0.9, hoverRadius = 0.4, variant = "glass", fill, pattern, tone, image, reveal = "rise", revealDuration = 0.9, dissolveCell = 14, trigger = "mount", tilt = true, tiltMax = 10, scramble = true, chars = "~-=^_", glow = true, align = "left", minHeight = 250, playKey = 0, className = "", }) {
21
+ const hover = textHover ?? legacyHover ?? "trail";
22
+ const card = useRef(null);
23
+ const bg = useRef(null);
24
+ const fx = useRef(null);
25
+ const art = useRef(null);
26
+ const h3 = useRef(null);
27
+ const redraw = useRef(() => { });
28
+ const tokens = useTokens(card);
29
+ // Al cambiar el tema (tokens) solo se repinta el fondo: no se repite el revelado
30
+ useEffect(() => {
31
+ redraw.current();
32
+ }, [tokens]);
33
+ useEffect(() => {
34
+ const el = card.current;
35
+ const bgc = bg.current;
36
+ const fxc = fx.current;
37
+ const artEl = art.current;
38
+ const titleEl = h3.current;
39
+ if (!el || !bgc || !fxc || !artEl || !titleEl)
40
+ return;
41
+ let disposed = false;
42
+ const cleanups = [];
43
+ const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
44
+ const coarse = window.matchMedia("(pointer: coarse)").matches;
45
+ (async () => {
46
+ const [{ gsap }, { ScrambleTextPlugin }, core] = await Promise.all([
47
+ import("gsap"),
48
+ import("gsap/ScrambleTextPlugin"),
49
+ import("asciify-engine/core"),
50
+ ]);
51
+ if (disposed)
52
+ return;
53
+ gsap.registerPlugin(ScrambleTextPlugin);
54
+ const bctx = bgc.getContext("2d");
55
+ const fctx = fxc.getContext("2d");
56
+ artEl.textContent = showNumeral ? core.asciifyText(`0${index}`, { char: glyph }) : "";
57
+ // ---------- fondo de texto con hover de asciify-engine ----------
58
+ const pos = { x: 0.5, y: 0.5 };
59
+ let intensity = 0;
60
+ let target = 0;
61
+ let raf = 0;
62
+ const t0 = performance.now();
63
+ const drawBg = () => {
64
+ bctx.clearRect(0, 0, bgc.width, bgc.height);
65
+ if (background === "field") {
66
+ const t = reduce ? 0 : ((performance.now() - t0) / 1000) * speed;
67
+ drawCardField(bctx, bgc.width, bgc.height, t, {
68
+ field,
69
+ charset,
70
+ color: fieldColor,
71
+ hover: fieldHover,
72
+ size: tileSize,
73
+ opacity: tileOpacity / 255,
74
+ seed: index * 13.7,
75
+ glyph,
76
+ colors: { mut: token(el, "--mut", "#8899aa"), acc: token(el, "--acc", "#ffffff"), acc2: token(el, "--acc2", "#cccccc") },
77
+ }, { x: pos.x, y: pos.y, intensity });
78
+ return;
79
+ }
80
+ if (background !== "text")
81
+ return;
82
+ core.renderTextBackground(bctx, bgc.width, bgc.height, tile || " ", {
83
+ fontSize: tileSize,
84
+ color: token(el, "--mut", "#8899aa"),
85
+ opacity: tileOpacity,
86
+ hoverEffect: hover,
87
+ hoverStrength,
88
+ hoverRadius,
89
+ hoverColor: token(el, "--acc", "#ffffff"),
90
+ }, intensity > 0.02 ? { x: pos.x, y: pos.y, intensity } : null);
91
+ };
92
+ redraw.current = drawBg;
93
+ // El campo animado corre a ~30 fps y solo mientras la tarjeta se ve; el resto solo mientras hay hover
94
+ const fieldAnimated = background === "field" && animate && !reduce && ANIMATED_FIELDS.has(field);
95
+ let visible = false;
96
+ let last = 0;
97
+ const loop = (now) => {
98
+ intensity += (target - intensity) * 0.18;
99
+ if (now - last > 33 || intensity > 0.02) {
100
+ last = now;
101
+ drawBg();
102
+ }
103
+ raf = (fieldAnimated && visible) || intensity > 0.02 || target > 0 ? requestAnimationFrame(loop) : 0;
104
+ };
105
+ if (fieldAnimated) {
106
+ const vio = new IntersectionObserver(([e]) => {
107
+ visible = e.isIntersecting;
108
+ if (visible && !raf)
109
+ raf = requestAnimationFrame(loop);
110
+ });
111
+ vio.observe(el);
112
+ cleanups.push(() => vio.disconnect());
113
+ }
114
+ const kick = () => {
115
+ if (!raf)
116
+ raf = requestAnimationFrame(loop);
117
+ };
118
+ cleanups.push(() => {
119
+ cancelAnimationFrame(raf);
120
+ redraw.current = () => { };
121
+ });
122
+ // ---------- disolución ASCII ----------
123
+ const k = { v: reveal === "dissolve" && !reduce ? 0 : 1 };
124
+ const seed = index * 977;
125
+ const drawDissolve = (time) => {
126
+ fctx.clearRect(0, 0, fxc.width, fxc.height);
127
+ if (k.v >= 1)
128
+ return;
129
+ const cell = dissolveCell;
130
+ fctx.font = `${Math.max(8, cell - 3)}px monospace`;
131
+ fctx.textBaseline = "top";
132
+ const bgCol = token(el, "--bg", "#000");
133
+ const a1 = token(el, "--acc", "#fff");
134
+ const a2 = token(el, "--acc2", "#ccc");
135
+ for (let cy = 0; cy * cell < fxc.height; cy++) {
136
+ for (let cx = 0; cx * cell < fxc.width; cx++) {
137
+ const hh = hash(seed + cx * 31 + cy * 17);
138
+ if (k.v < hh) {
139
+ fctx.fillStyle = bgCol;
140
+ fctx.fillRect(cx * cell, cy * cell, cell, cell);
141
+ fctx.fillStyle = hash(seed + cx + cy * 7 + Math.floor(time * 12)) > 0.5 ? a1 : a2;
142
+ fctx.globalAlpha = 0.35 + 0.65 * (1 - hh + k.v * 0.5);
143
+ fctx.fillText(chars[Math.floor(hash(cx * 3 + cy + time * 7) * chars.length)] ?? "#", cx * cell + 3, cy * cell + 2);
144
+ fctx.globalAlpha = 1;
145
+ }
146
+ else if (k.v - hh < 0.07) {
147
+ fctx.fillStyle = a1;
148
+ fctx.globalAlpha = 0.5;
149
+ fctx.fillRect(cx * cell, cy * cell, cell, cell);
150
+ fctx.globalAlpha = 1;
151
+ }
152
+ }
153
+ }
154
+ };
155
+ const size = () => {
156
+ const w = el.clientWidth;
157
+ const h = el.clientHeight;
158
+ for (const c of [bgc, fxc]) {
159
+ c.width = w;
160
+ c.height = h;
161
+ }
162
+ drawBg();
163
+ drawDissolve(0);
164
+ };
165
+ const ro = new ResizeObserver(size);
166
+ ro.observe(el);
167
+ cleanups.push(() => ro.disconnect());
168
+ // ---------- estado inicial y revelado ----------
169
+ gsap.set(el, { clearProps: "clipPath,opacity,visibility,transform" });
170
+ const animated = !reduce && reveal !== "none";
171
+ if (animated && reveal === "wipe")
172
+ gsap.set(el, { clipPath: "inset(0 100% 0 0)" });
173
+ if (animated && reveal === "rise")
174
+ gsap.set(el, { autoAlpha: 0, y: 60 });
175
+ if (animated)
176
+ gsap.set([artEl], { autoAlpha: 0 });
177
+ gsap.set(el, { transformPerspective: 900 });
178
+ const play = () => {
179
+ if (!animated)
180
+ return;
181
+ if (reveal === "wipe")
182
+ gsap.to(el, { clipPath: "inset(0 0% 0 0)", duration: revealDuration, ease: "power3.inOut" });
183
+ else if (reveal === "rise")
184
+ gsap.to(el, { autoAlpha: 1, y: 0, duration: revealDuration, ease: "power3.out" });
185
+ else {
186
+ const t = { v: 0 };
187
+ k.v = 0;
188
+ gsap.to(k, { v: 1, duration: revealDuration * 1.5, ease: "power1.inOut", onUpdate: () => drawDissolve((t.v += 0.03)) });
189
+ }
190
+ gsap.to(artEl, { autoAlpha: 1, duration: 0.6, delay: 0.3 });
191
+ if (scramble)
192
+ gsap.fromTo(titleEl, { scrambleText: { text: " " } }, { duration: 1.1, delay: 0.2, scrambleText: { text: title, chars, revealDelay: 0.15, speed: 0.6 }, ease: "none" });
193
+ };
194
+ if (trigger === "inview" && animated) {
195
+ const io = new IntersectionObserver(([e]) => e.isIntersecting && (play(), io.disconnect()), { threshold: 0.3 });
196
+ io.observe(el);
197
+ cleanups.push(() => io.disconnect());
198
+ }
199
+ else {
200
+ play();
201
+ }
202
+ // ---------- ratón ----------
203
+ if (!coarse) {
204
+ const rx = gsap.quickTo(el, "rotationX", { duration: 0.5, ease: "power3.out" });
205
+ const ry = gsap.quickTo(el, "rotationY", { duration: 0.5, ease: "power3.out" });
206
+ const move = (e) => {
207
+ const r = el.getBoundingClientRect();
208
+ const nx = (e.clientX - r.left) / r.width;
209
+ const ny = (e.clientY - r.top) / r.height;
210
+ pos.x = nx;
211
+ pos.y = ny;
212
+ target = 1;
213
+ kick();
214
+ if (tilt && !reduce) {
215
+ rx((0.5 - ny) * tiltMax);
216
+ ry((nx - 0.5) * tiltMax * 1.2);
217
+ }
218
+ el.style.setProperty("--mx", `${nx * 100}%`);
219
+ el.style.setProperty("--my", `${ny * 100}%`);
220
+ };
221
+ const enter = () => {
222
+ if (scramble && !reduce)
223
+ gsap.to(titleEl, { duration: 0.7, scrambleText: { text: title, chars, speed: 0.6 }, ease: "none" });
224
+ };
225
+ const leave = () => {
226
+ target = 0;
227
+ kick();
228
+ rx(0);
229
+ ry(0);
230
+ };
231
+ el.addEventListener("pointermove", move);
232
+ el.addEventListener("pointerenter", enter);
233
+ el.addEventListener("pointerleave", leave);
234
+ cleanups.push(() => {
235
+ el.removeEventListener("pointermove", move);
236
+ el.removeEventListener("pointerenter", enter);
237
+ el.removeEventListener("pointerleave", leave);
238
+ });
239
+ }
240
+ cleanups.push(() => {
241
+ gsap.killTweensOf([el, artEl, titleEl, k]);
242
+ gsap.set(el, { clearProps: "transform,opacity,visibility,clipPath" });
243
+ titleEl.textContent = title;
244
+ });
245
+ })();
246
+ return () => {
247
+ disposed = true;
248
+ cleanups.reverse().forEach((f) => f());
249
+ };
250
+ }, [title, index, showNumeral, glyph, background, field, charset, fieldColor, fieldHover, animate, speed, tile, tileSize, tileOpacity, hover, hoverStrength, hoverRadius, reveal, revealDuration, dissolveCell, trigger, tilt, tiltMax, scramble, chars, playKey]);
251
+ const f = fillProps({ fill, pattern, tone, image });
252
+ return (_jsxs("article", { ref: card, className: `ui-card ui-surface ${f.className} ${vcls(variant)} ${glow ? "ui-card--glowon" : ""} ${align === "center" ? "ui-card--center" : ""} ${className}`, style: { minHeight, ...f.style }, "data-corner": glyph, children: [background === "scene" && (_jsx(AsciiBackground, { scene: scene, asciiStyle: sceneStyle, cellSize: Math.max(4, Math.round(tileSize * 0.7)), palette: "tint", tintAmount: 0.7, asciiHover: "none", bloom: 0, vignette: 0.4, fps: 30, opacity: Math.max(0.1, tileOpacity / 255) })), _jsx("canvas", { ref: bg, className: "ui-card__bg", "aria-hidden": true }), _jsx("canvas", { ref: fx, className: "ui-card__fx", "aria-hidden": true }), _jsx("div", { className: "ui-card__glow", "aria-hidden": true }), _jsxs("div", { className: "ui-card__inner", children: [_jsx("pre", { ref: art, className: "ui-card__art", "aria-hidden": true }), _jsx("h3", { ref: h3, children: title }, title), _jsx("p", { children: text }), meta && _jsx("span", { className: "ui-card__meta", children: meta })] })] }));
253
+ }
@@ -0,0 +1,18 @@
1
+ import { type Variant } from "./variants.js";
2
+ export type AsciiChartProps = {
3
+ /** valores separados por comas */
4
+ data?: string;
5
+ /** etiquetas separadas por comas (una por valor) */
6
+ labels?: string;
7
+ kind?: "bars" | "hbars" | "spark" | "area";
8
+ /** filas de altura del gráfico vertical */
9
+ height?: number;
10
+ fillChar?: string;
11
+ /** anima el crecimiento al montar y al cambiar `playKey` */
12
+ animate?: boolean;
13
+ playKey?: number;
14
+ variant?: Variant;
15
+ className?: string;
16
+ };
17
+ /** Gráfico dibujado con caracteres: barras verticales, horizontales, sparkline o área. */
18
+ export default function AsciiChart({ data, labels, kind, height, fillChar, animate, playKey, variant, className }: AsciiChartProps): import("react").JSX.Element;
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useMemo, useState } from "react";
4
+ import { vcls } from "./variants.js";
5
+ const SPARK = "▁▂▃▄▅▆▇█";
6
+ /** Gráfico dibujado con caracteres: barras verticales, horizontales, sparkline o área. */
7
+ export default function AsciiChart({ data = "12, 18, 9, 24, 31, 27, 40, 36", labels = "L,M,X,J,V,S,D,L", kind = "bars", height = 10, fillChar = "█", animate = true, playKey = 0, variant = "terminal", className = "" }) {
8
+ const values = useMemo(() => data.split(",").map((s) => parseFloat(s)).filter((n) => Number.isFinite(n)), [data]);
9
+ const names = useMemo(() => labels.split(",").map((s) => s.trim()), [labels]);
10
+ const [k, setK] = useState(animate ? 0 : 1);
11
+ useEffect(() => {
12
+ if (!animate || window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
13
+ setK(1);
14
+ return;
15
+ }
16
+ setK(0);
17
+ let raf = 0;
18
+ const t0 = performance.now();
19
+ const tick = (now) => {
20
+ const p = Math.min(1, (now - t0) / 900);
21
+ setK(1 - Math.pow(1 - p, 3));
22
+ if (p < 1)
23
+ raf = requestAnimationFrame(tick);
24
+ };
25
+ raf = requestAnimationFrame(tick);
26
+ return () => cancelAnimationFrame(raf);
27
+ }, [animate, playKey, data, kind]);
28
+ const max = Math.max(1, ...values);
29
+ const fc = (fillChar || "#")[0];
30
+ let art = "";
31
+ let foot = "";
32
+ if (kind === "bars" || kind === "area") {
33
+ const H = Math.max(3, height);
34
+ const cols = values.map((v) => Math.max(0, Math.round((v / max) * H * k)));
35
+ for (let r = H; r >= 1; r--)
36
+ art += cols.map((c) => (c >= r ? (kind === "area" ? `${fc}${fc}${fc}` : ` ${fc} `) : " ")).join(kind === "area" ? "" : " ") + "\n";
37
+ foot = names.map((n) => (n || " ").slice(0, 3).padStart(2).padEnd(3)).join(kind === "area" ? "" : " ");
38
+ }
39
+ else if (kind === "hbars") {
40
+ const W = 28;
41
+ art = values.map((v, i) => `${(names[i] || "").padEnd(4)}${fc.repeat(Math.max(0, Math.round((v / max) * W * k))).padEnd(W)} ${Math.round(v * k)}`).join("\n");
42
+ }
43
+ else {
44
+ art = values.map((v) => SPARK[Math.max(0, Math.min(SPARK.length - 1, Math.floor((v / max) * (SPARK.length - 1) * k)))]).join("");
45
+ }
46
+ return (_jsxs("div", { className: `ui-chart ui-surface ${vcls(variant)} ${className}`, style: { padding: 16, width: "fit-content", maxWidth: "100%", overflow: "auto" }, children: [_jsx("pre", { role: "img", "aria-label": `Gráfico: ${data}`, children: art }), foot && _jsx("div", { className: "ui-chart__labels", children: foot })] }));
47
+ }
@@ -0,0 +1,15 @@
1
+ import { type Intent, type LegacyIntent } from "./intent.js";
2
+ import { type Variant } from "./variants.js";
3
+ export type BadgeProps = {
4
+ text: string;
5
+ variant?: Variant;
6
+ /** color semántico, el mismo vocabulario que Button, Alert, TextField y Toast (ver intent.ts) */
7
+ intent?: Intent | LegacyIntent;
8
+ /** @deprecated nombre antiguo de `intent` (aceptaba `warn`); se mantiene por compatibilidad */
9
+ tone?: Intent | LegacyIntent;
10
+ size?: "md" | "lg";
11
+ dot?: boolean;
12
+ className?: string;
13
+ };
14
+ /** Etiqueta de estado con color semántico (`intent`). */
15
+ export default function Badge({ text, variant, intent, tone, size, dot, className }: BadgeProps): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { intentCls, toIntent } from "./intent.js";
3
+ import { vcls } from "./variants.js";
4
+ /** Etiqueta de estado con color semántico (`intent`). */
5
+ export default function Badge({ text, variant = "glass", intent, tone, size = "md", dot = false, className = "" }) {
6
+ const i = toIntent(intent ?? tone, "accent");
7
+ return (_jsxs("span", { className: `ui-badge ${intentCls(i)} ${size === "lg" ? "ui-badge--lg" : ""} ${vcls(variant)} ${className}`, children: [dot && _jsx("i", { className: "ui-badge__dot", "aria-hidden": true }), text] }));
8
+ }
@@ -0,0 +1,25 @@
1
+ import { type Tone } from "./variants.js";
2
+ export type BitmapTextProps = {
3
+ text: string;
4
+ /** "Bitmap" (fuente 7×7 de asciify-engine) o una fuente FIGlet */
5
+ font?: string;
6
+ /** carácter con el que se dibuja (solo fuente Bitmap) */
7
+ char?: string;
8
+ scale?: number;
9
+ /** tamaño en px de cada carácter */
10
+ fontSize?: number;
11
+ /** @deprecated usa `fontSize` */
12
+ size?: number;
13
+ tone?: Tone;
14
+ align?: "left" | "center" | "right";
15
+ glow?: boolean;
16
+ /** intensidad del halo en px */
17
+ glowSize?: number;
18
+ animate?: "none" | "flicker" | "scan";
19
+ className?: string;
20
+ };
21
+ /**
22
+ * Titular en arte ASCII generado por asciify-engine (`asciifyText` / FIGlet). El color viene del token
23
+ * elegido en `tone`; el texto original queda accesible mediante `aria-label`.
24
+ */
25
+ export default function BitmapText({ text, font, char, scale, fontSize, size: legacySize, tone, align, glow, glowSize, animate, className, }: BitmapTextProps): import("react").JSX.Element;
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { bannerLines } from "../../lib/text/banner.js";
5
+ import { tcls } from "./variants.js";
6
+ /**
7
+ * Titular en arte ASCII generado por asciify-engine (`asciifyText` / FIGlet). El color viene del token
8
+ * elegido en `tone`; el texto original queda accesible mediante `aria-label`.
9
+ */
10
+ export default function BitmapText({ text, font = "Bitmap", char = "#", scale = 1, fontSize, size: legacySize, tone = "acc", align = "left", glow = true, glowSize = 8, animate = "none", className = "", }) {
11
+ const size = fontSize ?? legacySize ?? 11;
12
+ const [lines, setLines] = useState([text]);
13
+ useEffect(() => {
14
+ let live = true;
15
+ bannerLines(text || " ", font, { char, scale }).then((l) => live && setLines(l));
16
+ return () => {
17
+ live = false;
18
+ };
19
+ }, [text, font, char, scale]);
20
+ return (_jsx("pre", { role: "img", "aria-label": text, className: `ui-bitmap ${glow ? "ui-bitmap--glow" : ""} ui-bitmap--${animate} ${tcls(tone)} ${className}`, style: { fontSize: size, lineHeight: `${size}px`, textAlign: align, textShadow: glow ? `0 0 ${glowSize}px var(--tone, var(--acc))` : undefined }, children: lines.join("\n") }));
21
+ }
@@ -0,0 +1,33 @@
1
+ import { type CardFill, type CardPattern, type CardTone } from "./fill.js";
2
+ import { type Variant } from "./variants.js";
3
+ export type BlogCardProps = {
4
+ category?: string;
5
+ title?: string;
6
+ excerpt?: string;
7
+ date?: string;
8
+ readTime?: string;
9
+ /** autor; con él se pinta un avatar de iniciales en el pie */
10
+ author?: string;
11
+ /** imagen de portada: URL/ruta o `gen:N` (escena pixel art de ejemplo) */
12
+ image?: string;
13
+ /** qué va en la cabecera: la imagen, una trama de CSS, el patrón de caracteres o nada. Por defecto, la imagen si hay */
14
+ media?: "image" | "pattern" | "glyph" | "none";
15
+ /** trama de la cabecera con `media="pattern"` */
16
+ pattern?: CardPattern;
17
+ /** carácter del patrón con `media="glyph"` */
18
+ glyph?: string;
19
+ /**
20
+ * stacked: cabecera arriba · horizontal: cabecera a la izquierda (se apila sola si no cabe) ·
21
+ * overlay: la imagen ocupa toda la tarjeta y el texto va encima · minimal: sin cabecera, solo texto
22
+ */
23
+ layout?: "stacked" | "horizontal" | "overlay" | "minimal";
24
+ /** fondo de la tarjeta (ver fill.ts); con `overlay` y una imagen, la imagen es el fondo */
25
+ fill?: CardFill;
26
+ tone?: CardTone;
27
+ /** si se pasa, toda la tarjeta es un enlace */
28
+ href?: string;
29
+ variant?: Variant;
30
+ className?: string;
31
+ };
32
+ /** Tarjeta de artículo: cabecera (imagen, trama o caracteres), categoría, titular, extracto, autor y meta. */
33
+ export default function BlogCard({ category, title, excerpt, date, readTime, author, image, media, pattern, glyph, layout, fill, tone, href, variant, className, }: BlogCardProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { resolveImage } from "../../lib/ui/placeholder.js";
3
+ import { fillProps } from "./fill.js";
4
+ import { vcls } from "./variants.js";
5
+ /** Tarjeta de artículo: cabecera (imagen, trama o caracteres), categoría, titular, extracto, autor y meta. */
6
+ export default function BlogCard({ category = "Técnica", title = "Cinco errores al remar que te frenan la primera ola", excerpt = "El remo cuenta más que la fuerza: la postura y el timing son lo que de verdad te sube a la tabla.", date = "12 mar 2026", readTime = "4 min", author = "", image = "", media, pattern = "dots", glyph = "~", layout = "stacked", fill = "surface", tone = "acc", href, variant = "glass", className = "", }) {
7
+ const head = layout === "minimal" ? "none" : (media ?? (image ? "image" : "pattern"));
8
+ const overlayImage = layout === "overlay" && head === "image" && image;
9
+ const f = fillProps({ fill: overlayImage ? "image" : layout === "overlay" && fill === "surface" ? "gradient" : fill, pattern, tone, image });
10
+ const Root = href ? "a" : "article";
11
+ const initials = author.split(" ").map((w) => w[0]).filter(Boolean).slice(0, 2).join("").toUpperCase();
12
+ return (_jsxs(Root, { href: href, className: `ui-blog ui-blog--${layout} ${href ? "ui-blog--link" : ""} ui-surface ${f.className} ${vcls(variant)} ${className}`, style: f.style, children: [head !== "none" && layout !== "overlay" && (_jsx("div", { className: `ui-blog__media ui-blog__media--${head} ${head === "pattern" ? `ui-pat--${pattern}` : ""}`, "aria-hidden": true, children: head === "image" && image ? _jsx("img", { src: resolveImage(image), alt: "", loading: "lazy", decoding: "async" }) : head === "glyph" ? (glyph || "~")[0].repeat(220) : null })), _jsxs("div", { className: "ui-blog__body", children: [category && _jsx("span", { className: "ui-blog__cat", children: category }), _jsx("h4", { children: title }), excerpt && _jsx("p", { children: excerpt }), _jsxs("div", { className: "ui-blog__meta", children: [author && (_jsxs("span", { className: "ui-blog__author", children: [_jsx("span", { className: "ui-blog__avatar", "aria-hidden": true, children: initials }), author] })), date && _jsx("span", { children: date }), readTime && _jsxs("span", { children: [readTime, " de lectura"] }), href && _jsx("span", { className: "ui-blog__more", "aria-hidden": true, children: "Leer \u2192" })] })] })] }));
13
+ }
@@ -0,0 +1,9 @@
1
+ import { type Variant } from "./variants.js";
2
+ export type BreadcrumbsProps = {
3
+ items?: string;
4
+ separator?: string;
5
+ variant?: Variant;
6
+ className?: string;
7
+ };
8
+ /** Ruta de navegación. El último elemento es la página actual: texto, sin enlace. */
9
+ export default function Breadcrumbs({ items, separator, variant, className }: BreadcrumbsProps): import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { vcls } from "./variants.js";
3
+ /** Ruta de navegación. El último elemento es la página actual: texto, sin enlace. */
4
+ export default function Breadcrumbs({ items = "Inicio, Cursos, Iniciación al surf", separator = "/", variant = "minimal", className = "" }) {
5
+ const list = items.split(",").map((s) => s.trim()).filter(Boolean);
6
+ return (_jsx("nav", { "aria-label": "Ruta de navegaci\u00F3n", className: `ui-crumbs ${vcls(variant)} ${className}`, children: list.map((item, i) => (_jsxs("span", { className: "ui-crumbs__item", children: [i === list.length - 1 ? (_jsx("span", { "aria-current": "page", children: item })) : (_jsx("button", { type: "button", className: "ui-crumbs__link", children: item })), i < list.length - 1 && (_jsx("span", { className: "ui-crumbs__sep", "aria-hidden": true, children: separator }))] }, item + i))) }));
7
+ }
@@ -0,0 +1,74 @@
1
+ import { type AriaAttributes } from "react";
2
+ import { type Intent } from "./intent.js";
3
+ import { type Variant } from "./variants.js";
4
+ /** Color del botón: el vocabulario común de todo el kit (ver intent.ts). */
5
+ export declare const BUTTON_INTENTS: readonly ["accent", "neutral", "success", "info", "warning", "danger"];
6
+ export type ButtonIntent = Intent;
7
+ /** Énfasis: primary = relleno · secondary = superficie del estilo · outline = solo borde · ghost = solo texto · link = enlace */
8
+ export declare const BUTTON_EMPHASES: readonly ["primary", "secondary", "outline", "ghost", "link"];
9
+ export type ButtonEmphasis = (typeof BUTTON_EMPHASES)[number];
10
+ /** @deprecated usa `BUTTON_EMPHASES` / `ButtonEmphasis` */
11
+ export declare const BUTTON_TONES: readonly ["primary", "secondary", "outline", "ghost", "link"];
12
+ /** @deprecated usa `ButtonEmphasis` */
13
+ export type ButtonTone = ButtonEmphasis;
14
+ export type ButtonProps = {
15
+ /** texto del botón; con `iconOnly` es la etiqueta accesible (aria-label) y no se pinta */
16
+ label: string;
17
+ variant?: Variant;
18
+ /** énfasis: primary = relleno · secondary = superficie · outline = borde · ghost = texto · link = enlace */
19
+ emphasis?: ButtonEmphasis;
20
+ /** @deprecated usa `emphasis` */
21
+ tone?: ButtonEmphasis;
22
+ intent?: ButtonIntent;
23
+ size?: "sm" | "md" | "lg";
24
+ /** carácter decorativo junto al texto (→, +, >…), o un icono pixel art con `icon:heart` (ver Icon) */
25
+ glyph?: string;
26
+ glyphPosition?: "start" | "end";
27
+ /** botón cuadrado solo con `glyph`; `label` pasa a ser su aria-label */
28
+ iconOnly?: boolean;
29
+ fullWidth?: boolean;
30
+ disabled?: boolean;
31
+ /** estado pulsado (botones conmutables, filtros, barra de herramientas): pinta el estado y pone aria-pressed */
32
+ active?: boolean;
33
+ /** muestra un indicador de carga, pone aria-busy y bloquea el clic */
34
+ loading?: boolean;
35
+ /** si se pasa, se pinta como enlace `<a>` con el aspecto del botón */
36
+ href?: string;
37
+ /** "submit" para enviar el `<form>` que lo contiene (ver `ContactForm`) */
38
+ type?: "button" | "submit" | "reset";
39
+ onClick?: () => void;
40
+ className?: string;
41
+ } & AriaAttributes;
42
+ /**
43
+ * Botón del sistema. La variante decide superficie, borde, radio, sombra y tipografía; `emphasis` el énfasis e `intent`
44
+ * el color (el intent sustituye `--acc` solo dentro del botón, así que funciona igual en los 7 estilos).
45
+ */
46
+ declare const Button: import("react").ForwardRefExoticComponent<{
47
+ /** texto del botón; con `iconOnly` es la etiqueta accesible (aria-label) y no se pinta */
48
+ label: string;
49
+ variant?: Variant;
50
+ /** énfasis: primary = relleno · secondary = superficie · outline = borde · ghost = texto · link = enlace */
51
+ emphasis?: ButtonEmphasis;
52
+ /** @deprecated usa `emphasis` */
53
+ tone?: ButtonEmphasis;
54
+ intent?: ButtonIntent;
55
+ size?: "sm" | "md" | "lg";
56
+ /** carácter decorativo junto al texto (→, +, >…), o un icono pixel art con `icon:heart` (ver Icon) */
57
+ glyph?: string;
58
+ glyphPosition?: "start" | "end";
59
+ /** botón cuadrado solo con `glyph`; `label` pasa a ser su aria-label */
60
+ iconOnly?: boolean;
61
+ fullWidth?: boolean;
62
+ disabled?: boolean;
63
+ /** estado pulsado (botones conmutables, filtros, barra de herramientas): pinta el estado y pone aria-pressed */
64
+ active?: boolean;
65
+ /** muestra un indicador de carga, pone aria-busy y bloquea el clic */
66
+ loading?: boolean;
67
+ /** si se pasa, se pinta como enlace `<a>` con el aspecto del botón */
68
+ href?: string;
69
+ /** "submit" para enviar el `<form>` que lo contiene (ver `ContactForm`) */
70
+ type?: "button" | "submit" | "reset";
71
+ onClick?: () => void;
72
+ className?: string;
73
+ } & AriaAttributes & import("react").RefAttributes<HTMLElement>>;
74
+ export default Button;