@axzydev/axzy_ui_system 1.5.0 → 1.5.2

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.
@@ -1,20 +1,28 @@
1
1
  /**
2
- * Marco de las páginas de componente del sandbox (`#ui-system/<grupo>/<item>`):
3
- * cabecera de la hoja, vitrina interactiva (vista previa / código), panel de
4
- * propiedades y documentación, y galería de variaciones.
2
+ * Marco de las páginas de componente del sandbox (`#ui-system/<grupo>/<item>`).
5
3
  *
6
- * Sigue `DESIGN.md` (AXZY Console): el bloque lo separan filetes de 1px, no
7
- * cajas dentro de cajas; los controles vienen del kit compartido
8
- * (`@/sandbox/ui` y `@/sandbox/controls`) para que el marco no introduzca
9
- * colores que no pasan AA.
4
+ * Diseño «documentación viva»: cada ejemplo es un **contenedor con cabecera
5
+ * propia** (número, título y la acción de ver el código siempre a la vista), el
6
+ * código se despliega dentro del mismo contenedor, los controles viven en un
7
+ * grid compacto bajo el demo y la API (props, ejemplos, notas) está **siempre
8
+ * visible** en la columna derecha, sin pestañas.
9
+ *
10
+ * Sigue `DESIGN.md` (AXZY Console): filetes de 1px, mono para metadatos y un
11
+ * solo acento.
10
12
  */
11
13
 
12
14
  import React, { useState } from "react";
13
- import { FaBookOpen, FaCheck, FaCode, FaCog, FaCopy, FaEye } from "react-icons/fa";
15
+ import { FaBookOpen, FaCheck, FaCode, FaCopy, FaEye } from "react-icons/fa";
14
16
  import ITGrid from "../components/atoms/grid/grid";
15
17
  import { useITTheme } from "../components/theme-provider/themeProvider";
16
18
  import { ControlSegmentado } from "@/sandbox/controls";
17
- import { EYEBROW, FILETE, FOCO_CTA } from "@/sandbox/ui";
19
+ import {
20
+ BotonCopiar,
21
+ EYEBROW,
22
+ EjemploContenedor,
23
+ FILETE,
24
+ FOCO_CTA,
25
+ } from "@/sandbox/ui";
18
26
  import { useITTranslation } from "@/i18n";
19
27
 
20
28
  /**
@@ -52,6 +60,7 @@ export const CodeViewer: React.FC<{ code: string; compact?: boolean }> = ({ code
52
60
  </button>
53
61
  </div>
54
62
  <pre
63
+ tabIndex={0}
55
64
  className={`overflow-x-auto whitespace-pre-wrap p-4 font-mono text-xs leading-relaxed ${
56
65
  compact ? "max-h-[420px]" : ""
57
66
  } overflow-y-auto`}
@@ -98,32 +107,27 @@ export interface ShowcaseLayoutProps {
98
107
  description: string;
99
108
  /** Demo interactiva. */
100
109
  demo: React.ReactNode;
101
- /**
102
- * Panel de controles (lo construye cada showcase). Si se omite, la vitrina
103
- * ocupa todo el ancho y no se pinta panel: para páginas que solo muestran un
104
- * ejemplo o una receta.
105
- */
110
+ /** Controles del ejemplo (lo construye cada showcase). */
106
111
  controls?: React.ReactNode;
107
- /** Código fuente que se muestra en la pestaña de código. */
112
+ /** Código fuente del ejemplo principal. */
108
113
  code: string;
109
114
  /** Galería de variaciones y estados. */
110
115
  gallery?: React.ReactNode;
111
- /** Documentación opcional (añade la pestaña "Docs"). */
116
+ /** Documentación opcional (columna derecha). */
112
117
  doc?: ComponentDoc;
113
118
  /**
114
- * Ancho de la vitrina. `"columna"` (por defecto) la deja en 8/12 columnas con
115
- * el panel al lado; `"completo"` la lleva a las 12 y baja el panel, para demos
116
- * que son un layout entero (ITLayout, pantallas de ejemplo) y se recortaban.
117
- * @default "columna"
119
+ * Ancho mínimo (px) del demo dentro de la vitrina. Los demos que son un layout
120
+ * entero (`ITLayout`, pantallas de ejemplo) lo necesitan: por debajo de ~780px
121
+ * su propio contenido se recorta. La vitrina desplaza en horizontal lo que
122
+ * sobre.
123
+ * @default 0
118
124
  */
119
- demoAncho?: "columna" | "completo";
125
+ demoMinAncho?: number;
120
126
  }
121
127
 
122
- type SandboxView = "preview" | "code";
123
-
124
128
  /**
125
- * Página de un componente del sandbox: cabecera, vitrina con vista previa y
126
- * código, panel lateral de propiedades/documentación y galería.
129
+ * Página de un componente del sandbox: cabecera, ejemplo principal con su código,
130
+ * controles en grid, API en la columna derecha y galería de variaciones.
127
131
  *
128
132
  * @example
129
133
  * ```tsx
@@ -139,20 +143,18 @@ export const ShowcaseLayout: React.FC<ShowcaseLayoutProps> = ({
139
143
  code,
140
144
  gallery,
141
145
  doc,
142
- demoAncho = "columna",
146
+ demoMinAncho = 0,
143
147
  }) => {
144
- const completo = demoAncho === "completo";
145
148
  const { t } = useITTranslation();
146
149
  const { resolvedTheme } = useITTheme();
147
- const [activeTab, setActiveTab] = useState<"controls" | "docs">(controls ? "controls" : "docs");
148
- const [sandboxView, setSandboxView] = useState<SandboxView>("preview");
149
- // Sin controles la vitrina se queda con todo el ancho.
150
- const hayPanel = Boolean(controls) || Boolean(doc);
150
+ const [sandboxView, setSandboxView] = useState<"preview" | "code">("preview");
151
+
152
+ const hayApi = Boolean(doc);
151
153
 
152
154
  return (
153
155
  <div className="animate-fadeIn pb-4">
154
- {/* ─── CABECERA DE LA HOJA ─── */}
155
- <header className={`border-b pb-7 ${FILETE}`}>
156
+ {/* ─── CABECERA ─── */}
157
+ <header className={`border-b pb-6 ${FILETE}`}>
156
158
  <p className={EYEBROW}>{t("showcase.layout.eyebrow")}</p>
157
159
  <h1 className="mt-2.5 font-display text-[32px] font-bold tracking-[-0.02em] text-slate-900 dark:text-white sm:text-[40px]">
158
160
  {title}
@@ -162,18 +164,21 @@ export const ShowcaseLayout: React.FC<ShowcaseLayoutProps> = ({
162
164
  </p>
163
165
  </header>
164
166
 
165
- <div className="pt-8">
167
+ <div className="pt-6">
166
168
  <ITGrid container columns={12} spacing={8}>
167
- {/* ── VITRINA ── */}
168
- <ITGrid item xs={12} md={completo || !hayPanel ? 12 : 8}>
169
- <section
170
- aria-label={t("showcase.layout.sandbox")}
171
- className={`overflow-hidden rounded-[10px] border ${FILETE}`}
169
+ {/* ── EJEMPLO PRINCIPAL + CONTROLES ── */}
170
+ <ITGrid item xs={12} md={hayApi ? 8 : 12}>
171
+ <EjemploContenedor
172
+ numero="01"
173
+ titulo={t("showcase.layout.sandbox")}
174
+ nota={doc?.summary}
175
+ sangrado
172
176
  >
173
- {/* Barra de la vitrina */}
174
- <div className={`flex flex-wrap items-center justify-between gap-3 border-b px-4 py-2.5 ${FILETE}`}>
175
- <h2 className={EYEBROW}>{t("showcase.layout.sandbox")}</h2>
176
-
177
+ {/* Barra del ejemplo: vista previa / código, siempre visible */}
178
+ <div
179
+ className={`flex flex-wrap items-center justify-between gap-3 border-b px-4 py-2.5 ${FILETE}`}
180
+ >
181
+ <span className={EYEBROW}>{t("showcase.layout.preview")}</span>
177
182
  <ControlSegmentado
178
183
  etiqueta={t("showcase.layout.sandbox")}
179
184
  valor={sandboxView}
@@ -189,145 +194,118 @@ export const ShowcaseLayout: React.FC<ShowcaseLayoutProps> = ({
189
194
  />
190
195
  </div>
191
196
 
192
- {/* Contenido */}
193
197
  {sandboxView === "preview" ? (
194
198
  <div
195
199
  data-theme={resolvedTheme}
196
- className="flex min-h-[280px] items-center justify-center overflow-x-auto bg-white p-6 dark:bg-slate-950 md:p-10"
200
+ tabIndex={0}
201
+ className="flex min-h-[220px] items-center justify-center overflow-x-auto bg-white p-6 dark:bg-slate-950 md:p-8"
197
202
  >
198
- <div className="flex w-full justify-center">{demo}</div>
203
+ <div
204
+ className="flex w-full justify-center"
205
+ style={demoMinAncho ? { minWidth: `${demoMinAncho}px` } : undefined}
206
+ >
207
+ {demo}
208
+ </div>
199
209
  </div>
200
210
  ) : (
201
- <div className="p-3">
211
+ <div className="p-4">
202
212
  <CodeViewer code={code} compact />
203
213
  </div>
204
214
  )}
205
- </section>
215
+ </EjemploContenedor>
216
+
217
+ {controls && (
218
+ <section className={`mt-6 overflow-hidden rounded-[10px] border ${FILETE}`}>
219
+ <header
220
+ className={`flex items-center justify-between gap-3 border-b bg-slate-50/70 px-4 py-2.5 dark:bg-slate-950/40 ${FILETE}`}
221
+ >
222
+ <h2 className={EYEBROW}>{t("showcase.layout.controls")}</h2>
223
+ </header>
224
+ <div className="grid gap-4 p-4 sm:grid-cols-2 xl:grid-cols-3">{controls}</div>
225
+ </section>
226
+ )}
206
227
  </ITGrid>
207
228
 
208
- {/* ── PANEL LATERAL ── */}
209
- {hayPanel && (
210
- <ITGrid item xs={12} md={completo ? 12 : 4}>
211
- <div className={completo ? "" : "md:sticky md:top-4"}>
212
- <section
213
- aria-label={t("showcase.layout.properties")}
214
- className={`overflow-hidden rounded-[10px] border ${FILETE} ${
215
- completo ? "max-w-[880px]" : ""
216
- }`}
217
- >
218
- {doc ? (
219
- <div
220
- role="tablist"
221
- aria-label={t("showcase.layout.properties")}
222
- className={`flex items-stretch gap-1 border-b px-2 ${FILETE}`}
229
+ {/* ── API (siempre visible, sin pestañas) ── */}
230
+ {hayApi && (
231
+ <ITGrid item xs={12} md={4}>
232
+ <div className="md:sticky md:top-4">
233
+ <section className={`overflow-hidden rounded-[10px] border ${FILETE}`}>
234
+ <header
235
+ className={`flex items-center gap-2 border-b bg-slate-50/70 px-4 py-2.5 dark:bg-slate-950/40 ${FILETE}`}
223
236
  >
224
- {(
225
- [
226
- { id: "controls", label: t("showcase.layout.properties"), icono: <FaCog size={10} /> },
227
- { id: "docs", label: t("showcase.layout.docs"), icono: <FaBookOpen size={10} /> },
228
- ] as const
229
- ).map((tab) => {
230
- const activa = activeTab === tab.id;
231
- return (
232
- <button
233
- key={tab.id}
234
- type="button"
235
- role="tab"
236
- aria-selected={activa}
237
- onClick={() => setActiveTab(tab.id)}
238
- className={`-mb-px inline-flex items-center gap-2 border-b-2 px-3 py-2.5 font-mono text-[10px] font-medium uppercase tracking-[0.14em] transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/60 ${
239
- activa
240
- ? "border-primary-700 text-primary-700 dark:border-primary-500 dark:text-primary-500"
241
- : "border-transparent text-slate-500 hover:text-slate-900 dark:text-slate-400 dark:hover:text-white"
242
- }`}
243
- >
244
- {tab.icono}
245
- {tab.label}
246
- </button>
247
- );
248
- })}
249
- </div>
250
- ) : null}
237
+ <FaBookOpen size={11} className="text-primary-700 dark:text-primary-500" />
238
+ <h2 className={EYEBROW}>{t("showcase.layout.api")}</h2>
239
+ </header>
251
240
 
252
- {activeTab === "controls" && (
253
- <div
254
- className={`max-h-[calc(100vh-200px)] space-y-4 overflow-y-auto p-5 ${
255
- completo ? "it-panel-ancho max-w-[880px]" : ""
256
- }`}
257
- >
258
- {controls}
259
- </div>
260
- )}
261
-
262
- {doc && activeTab === "docs" && (
263
- <div
264
- className={`max-h-[calc(100vh-200px)] space-y-6 overflow-y-auto p-5 ${
265
- completo ? "it-panel-ancho max-w-[880px]" : ""
266
- }`}
267
- >
268
- <div>
269
- <h2 className={EYEBROW}>{t("showcase.layout.overview")}</h2>
270
- <p className="mt-2.5 text-[13px] leading-relaxed text-slate-700 dark:text-slate-300">
271
- {doc.summary}
241
+ <div tabIndex={0} className="max-h-[calc(100vh-220px)] space-y-6 overflow-y-auto p-4">
242
+ {doc?.description && (
243
+ <p className="text-[12.5px] leading-relaxed text-slate-600 dark:text-slate-300">
244
+ {doc.description}
272
245
  </p>
273
- {doc.description && (
274
- <p className="mt-2 text-[12px] leading-relaxed text-slate-500 dark:text-slate-400">
275
- {doc.description}
276
- </p>
277
- )}
278
- </div>
246
+ )}
279
247
 
280
- <div>
281
- <h2 className={EYEBROW}>{t("showcase.layout.props")}</h2>
282
- <dl className={`mt-3 border-t ${FILETE}`}>
283
- {doc.props.map((prop) => (
284
- <div key={prop.name} className={`border-b py-3 ${FILETE}`}>
285
- <dt className="flex flex-wrap items-baseline gap-x-2 font-mono text-[11px] font-semibold text-primary-700 dark:text-primary-500">
286
- {prop.name}
287
- {prop.required ? (
288
- <span className="text-danger-500" title={t("showcase.common.required")}>
289
- *
248
+ {!!doc?.props.length && (
249
+ <div>
250
+ <h3 className={EYEBROW}>{t("showcase.layout.props")}</h3>
251
+ <dl className={`mt-2.5 border-t ${FILETE}`}>
252
+ {doc.props.map((prop) => (
253
+ <div key={prop.name} className={`border-b py-2.5 ${FILETE}`}>
254
+ <dt className="flex flex-wrap items-baseline gap-x-2 font-mono text-[11px] font-semibold text-primary-700 dark:text-primary-500">
255
+ {prop.name}
256
+ {prop.required ? (
257
+ <span
258
+ className="text-danger-500"
259
+ title={t("showcase.common.required")}
260
+ >
261
+ *
262
+ </span>
263
+ ) : null}
264
+ <span className="font-mono text-[10px] font-normal text-slate-500 dark:text-slate-400">
265
+ {prop.type}
290
266
  </span>
291
- ) : null}
292
- <span className="font-mono text-[10px] font-normal text-slate-500 dark:text-slate-400">
293
- {prop.type}
294
- </span>
295
- <span className="font-mono text-[10px] font-normal text-slate-500 dark:text-slate-400">
296
- {`= ${prop.default || "—"}`}
297
- </span>
298
- </dt>
299
- <dd className="mt-1.5 text-[12px] leading-relaxed text-slate-600 dark:text-slate-300">
300
- {prop.description}
301
- </dd>
302
- </div>
303
- ))}
304
- </dl>
305
- </div>
267
+ <span className="font-mono text-[10px] font-normal text-slate-500 dark:text-slate-400">
268
+ {`= ${prop.default || "—"}`}
269
+ </span>
270
+ </dt>
271
+ <dd className="mt-1 text-[12px] leading-relaxed text-slate-600 dark:text-slate-300">
272
+ {prop.description}
273
+ </dd>
274
+ </div>
275
+ ))}
276
+ </dl>
277
+ </div>
278
+ )}
306
279
 
307
- {doc.examples && doc.examples.length > 0 && (
280
+ {doc?.examples && doc.examples.length > 0 && (
308
281
  <div>
309
- <h2 className={EYEBROW}>{t("showcase.layout.usageExamples")}</h2>
310
- <div className="mt-3 space-y-2">
282
+ <h3 className={EYEBROW}>{t("showcase.layout.usageExamples")}</h3>
283
+ <div className="mt-2.5 space-y-2">
311
284
  {doc.examples.map((example, i) => (
312
- <pre
313
- key={i}
314
- className="overflow-x-auto rounded-[10px] border border-slate-800 bg-slate-950 p-3 font-mono text-[10px] leading-relaxed text-slate-200"
315
- >
316
- <code>{example}</code>
317
- </pre>
285
+ <div key={i} className="relative">
286
+ <pre tabIndex={0} className="overflow-x-auto rounded-[10px] border border-slate-800 bg-slate-950 p-3 pr-10 font-mono text-[10px] leading-relaxed text-slate-200">
287
+ <code>{example}</code>
288
+ </pre>
289
+ <span className="absolute right-1.5 top-1.5">
290
+ <BotonCopiar
291
+ texto={example}
292
+ className="text-slate-500 hover:bg-slate-800 hover:text-white dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-white"
293
+ />
294
+ </span>
295
+ </div>
318
296
  ))}
319
297
  </div>
320
298
  </div>
321
299
  )}
322
300
 
323
- {doc.notes && doc.notes.length > 0 && (
301
+ {doc?.notes && doc.notes.length > 0 && (
324
302
  <div>
325
- <h2 className={EYEBROW}>{t("showcase.layout.notes")}</h2>
326
- <ul className={`mt-3 border-t ${FILETE}`}>
303
+ <h3 className={EYEBROW}>{t("showcase.layout.notes")}</h3>
304
+ <ul className={`mt-2.5 border-t ${FILETE}`}>
327
305
  {doc.notes.map((note, i) => (
328
306
  <li
329
307
  key={i}
330
- className={`border-b py-2.5 text-[12px] leading-relaxed text-slate-600 dark:text-slate-300 ${FILETE}`}
308
+ className={`border-b py-2 text-[12px] leading-relaxed text-slate-600 dark:text-slate-300 ${FILETE}`}
331
309
  >
332
310
  {note}
333
311
  </li>
@@ -336,19 +314,24 @@ export const ShowcaseLayout: React.FC<ShowcaseLayoutProps> = ({
336
314
  </div>
337
315
  )}
338
316
  </div>
339
- )}
340
- </section>
341
- </div>
342
- </ITGrid>
317
+ </section>
318
+ </div>
319
+ </ITGrid>
343
320
  )}
344
321
  </ITGrid>
345
322
  </div>
346
323
 
347
- {/* ─── GALERÍA ─── */}
324
+ {/* ─── MÁS EJEMPLOS ─── */}
348
325
  {gallery && (
349
- <section className={`mt-12 border-t pt-8 ${FILETE}`} aria-label={t("showcase.layout.gallery")}>
350
- <h2 className={EYEBROW}>{t("showcase.layout.gallery")}</h2>
351
- <div className="mt-5">{gallery}</div>
326
+ <section
327
+ className={`mt-12 border-t pt-8 ${FILETE}`}
328
+ aria-label={t("showcase.layout.gallery")}
329
+ >
330
+ <p className={EYEBROW}>{t("showcase.layout.gallery")}</p>
331
+ <h2 className="mt-2 font-display text-[22px] font-bold tracking-[-0.02em] text-slate-900 dark:text-white">
332
+ {t("showcase.layout.galleryTitle")}
333
+ </h2>
334
+ <div className="mt-6 space-y-6">{gallery}</div>
352
335
  </section>
353
336
  )}
354
337
  </div>
@@ -35,6 +35,7 @@ import {
35
35
  } from "../index";
36
36
  import type { ITSidebarProps } from "../index";
37
37
  import { ShowcaseLayout, CodeViewer } from "./ShowcaseLayout";
38
+ import { EjemploContenedor } from "@/sandbox/ui";
38
39
  import { useITTranslation } from "@/i18n";
39
40
 
40
41
  // ─────────────────────────────────────────
@@ -533,6 +534,33 @@ export const CardShowcase = () => {
533
534
  </GallerySection>
534
535
  </ITStack>
535
536
  }
537
+ doc={{
538
+ summary: "Contenedor de tarjeta con imagen, título, cuerpo y pie de acciones opcionales; con onClick se vuelve interactivo.",
539
+ description: "Pieza base de composición para agrupar contenido relacionado. Borde, radio y sombra se adaptan al aspecto del tema (flat / soft).",
540
+ examples: [
541
+ '<ITCard title="Ingresos del mes" actions={<ITButton label="Ver detalle" size="sm" />}>$48.230</ITCard>',
542
+ '<ITCard title="Curso" image="/courses/ts.jpg" imageClassName="h-32" onClick={() => open(course.id)}>…</ITCard>',
543
+ '<ITCard className="max-w-sm"><ITText muted>Tarjeta estática, sin cabecera ni acciones.</ITText></ITCard>',
544
+ ],
545
+ props: [
546
+ { name: "onClick", type: "() => void", default: "—", description: "Al recibirlo la tarjeta se vuelve clicable: cursor pointer, transición de sombra y elevación en hover. Sin él es estática." },
547
+ { name: "title", type: "string", default: "—", description: "Título de la cabecera; se renderiza como h3 mediante ITText." },
548
+ { name: "image", type: "string", default: "—", description: "URL de la imagen superior, a ancho completo con h-48 object-cover." },
549
+ { name: "alt", type: "string", default: "t(\"card.imageAlt\")", description: "Texto alternativo de la imagen; si se omite usa la key i18n card.imageAlt." },
550
+ { name: "children", type: "ReactNode", default: "—", description: "Contenido del cuerpo, debajo del título." },
551
+ { name: "actions", type: "ReactNode", default: "—", description: "Pie de acciones separado por un borde superior y anclado al fondo con mt-auto." },
552
+ { name: "className", type: "string", default: "—", description: "Clases del contenedor de la tarjeta." },
553
+ { name: "imageClassName", type: "string", default: "—", description: "Clases de la imagen; permite sobreescribir el h-48 por defecto." },
554
+ { name: "titleClassName", type: "string", default: "—", description: "Clases del título de la cabecera." },
555
+ { name: "contentClassName", type: "string", default: "—", description: "Clases del contenedor del cuerpo." },
556
+ { name: "actionClassName", type: "string", default: "—", description: "Clases del pie de acciones." },
557
+ ],
558
+ notes: [
559
+ "El aspecto del tema decide borde y sombra: en flat el borde es un hairline y solo hay sombra en hover si la tarjeta es clicable; en soft flota con --shadow-sm y sube a --shadow-lg con translateY(-2px).",
560
+ "Variables CSS: --it-card-bg, --it-card-border, --it-card-flat-border y --it-card-radius.",
561
+ "El padding es fijo (cuerpo 1.25rem, pie 1rem): no hay prop de tamaño.",
562
+ ],
563
+ }}
536
564
  />
537
565
  );
538
566
  };
@@ -909,6 +937,27 @@ export const TextShowcase = () => {
909
937
  </GallerySection>
910
938
  </ITStack>
911
939
  }
940
+ doc={{
941
+ summary: "Wrapper tipográfico semántico que renderiza cualquier elemento HTML (p, span, h1, label…) y reenvía los atributos estándar.",
942
+ description: "Aporta la capa de texto del sistema con el token muted; no impone clases tipográficas, así que tamaño, peso y color los define el className del consumidor.",
943
+ examples: [
944
+ '<ITText as="h1" className="text-2xl font-bold">Bienvenido</ITText>',
945
+ '<ITText as="p" muted className="text-sm">Descripción secundaria del panel.</ITText>',
946
+ '<ITText as="label" htmlFor="email">Correo electrónico</ITText>',
947
+ ],
948
+ props: [
949
+ { name: "children", type: "ReactNode", default: "—", description: "Contenido renderizado dentro del elemento." },
950
+ { name: "as", type: "ElementType", default: '"p"', description: "Elemento HTML a renderizar: p, span, h1, h2, label, code, etc." },
951
+ { name: "muted", type: "boolean", default: "false", description: "Aplica el color de texto atenuado (--color-text-muted) mediante style inline." },
952
+ { name: "htmlFor", type: "string", default: "—", description: "Asocia el texto con un campo de formulario; se reenvía como htmlFor cuando as es label." },
953
+ { name: "className", type: "string", default: "—", description: "Clases del elemento: definen tamaño, peso y color, porque el componente no añade ninguna." },
954
+ ],
955
+ notes: [
956
+ "Extiende HTMLAttributes<HTMLElement>, así que id, style, title, onClick, role y aria-* se reenvían al elemento renderizado.",
957
+ "muted se combina con el style propio: si el consumidor define color, gana el del consumidor.",
958
+ "Lo usan internamente otros componentes (avatar, button, badget, chip, checkbox, loader, radio, segmented-control, slider, textarea, tooltip) para etiquetas y textos.",
959
+ ],
960
+ }}
912
961
  />
913
962
  );
914
963
  };
@@ -1050,13 +1099,13 @@ export const LayoutShowcase = () => {
1050
1099
 
1051
1100
  return (
1052
1101
  <ShowcaseLayout
1053
- demoAncho="completo"
1102
+ demoMinAncho={780}
1054
1103
  title="ITLayout & ITNavbar"
1055
1104
  description="Chasis estructural del portal con barra superior y lateral colapsable. Totalmente responsivo con drawer móvil."
1056
1105
  code={code}
1057
1106
  demo={
1058
1107
  <div className="w-full h-[640px] rounded-xl overflow-hidden border border-slate-200 dark:border-slate-700 shadow-md">
1059
- <ITLayout topBar={topBar} sidebar={sidebar}>
1108
+ <ITLayout className="!h-full" topBar={topBar} sidebar={sidebar}>
1060
1109
  <ITStack spacing={5}>
1061
1110
  <ITPageHeader
1062
1111
  title={t("showcase.structure.navDashboard")}
@@ -1102,11 +1151,23 @@ export const LayoutShowcase = () => {
1102
1151
  }
1103
1152
  gallery={
1104
1153
  <ITStack spacing={8}>
1105
- <div>
1106
- <h3 className="mb-3 font-mono text-[11px] font-medium uppercase tracking-[0.14em] text-slate-500 dark:text-slate-400">
1107
- {t("showcase.structure.galleryNavbarStandalone")}
1108
- </h3>
1109
- <div className="overflow-hidden rounded-[10px] border border-slate-200 dark:border-slate-800">
1154
+ <EjemploContenedor
1155
+ numero="02"
1156
+ titulo={t("showcase.structure.galleryNavbarStandalone")}
1157
+ codigo={`<ITNavbar
1158
+ logoText="AXZY"
1159
+ navigationItems={[
1160
+ { id: "1", label: "Inicio", icon: <FaHome />, isActive: true },
1161
+ { id: "2", label: "Documentos", icon: <FaFileAlt /> },
1162
+ { id: "3", label: "Alertas", icon: <FaBell /> },
1163
+ ]}
1164
+ userMenu={{ userName: "Auditor AXZY", userEmail: "auditor@axzy.dev" }}
1165
+ >
1166
+ <Dashboard />
1167
+ </ITNavbar>`}
1168
+ sangrado
1169
+ >
1170
+ <div className="h-[380px] overflow-hidden [&>div]:!h-full">
1110
1171
  <ITNavbar
1111
1172
  logoText="AXZY"
1112
1173
  navigationItems={navbarItems}
@@ -1130,13 +1191,29 @@ export const LayoutShowcase = () => {
1130
1191
  </div>
1131
1192
  </ITNavbar>
1132
1193
  </div>
1133
- </div>
1194
+ </EjemploContenedor>
1134
1195
 
1135
- <div>
1136
- <h3 className="mb-3 font-mono text-[11px] font-medium uppercase tracking-[0.14em] text-slate-500 dark:text-slate-400">
1137
- {t("showcase.structure.galleryNavbarSubmenus")}
1138
- </h3>
1139
- <div className="overflow-hidden rounded-[10px] border border-slate-200 dark:border-slate-800">
1196
+ <EjemploContenedor
1197
+ numero="03"
1198
+ titulo={t("showcase.structure.galleryNavbarSubmenus")}
1199
+ codigo={`<ITNavbar
1200
+ logoText="Admin"
1201
+ navigationItems={[
1202
+ { id: "u", label: "Usuarios", icon: <FaUsers /> },
1203
+ {
1204
+ id: "s",
1205
+ label: "Ventas",
1206
+ icon: <FaShoppingCart />,
1207
+ subitems: [
1208
+ { id: "o", label: "Órdenes", action: () => {} },
1209
+ { id: "i", label: "Facturas", action: () => {} },
1210
+ ],
1211
+ },
1212
+ ]}
1213
+ />`}
1214
+ sangrado
1215
+ >
1216
+ <div className="h-[380px] overflow-hidden [&>div]:!h-full">
1140
1217
  <ITNavbar
1141
1218
  logoText="Admin"
1142
1219
  navigationItems={[
@@ -1165,13 +1242,23 @@ export const LayoutShowcase = () => {
1165
1242
  </div>
1166
1243
  </ITNavbar>
1167
1244
  </div>
1168
- </div>
1245
+ </EjemploContenedor>
1169
1246
 
1170
- <div>
1171
- <h3 className="mb-3 font-mono text-[11px] font-medium uppercase tracking-[0.14em] text-slate-500 dark:text-slate-400">
1172
- {t("showcase.structure.gallerySidebarBadges")}
1173
- </h3>
1174
- <div className="flex h-[320px] overflow-hidden rounded-[10px] border border-slate-200 dark:border-slate-800">
1247
+ <EjemploContenedor
1248
+ numero="04"
1249
+ titulo={t("showcase.structure.gallerySidebarBadges")}
1250
+ codigo={`<ITSidebar
1251
+ subitemConnector="dot"
1252
+ navigationItems={[
1253
+ { id: "home", label: "Inicio", icon: <FaHome />, isActive: true },
1254
+ { id: "inbox", label: "Bandeja", icon: <FaUsers />, badge: 12 },
1255
+ { id: "alerts", label: "Alertas", icon: <FaBell />, badge: 3 },
1256
+ ]}
1257
+ notification={{ count: 5, icon: <FaBell /> }}
1258
+ />`}
1259
+ sangrado
1260
+ >
1261
+ <div className="flex h-[320px] overflow-hidden [&>div]:!h-full">
1175
1262
  <ITSidebar
1176
1263
  visibleOnMobile
1177
1264
  className="h-full"
@@ -1200,7 +1287,7 @@ export const LayoutShowcase = () => {
1200
1287
  </p>
1201
1288
  </div>
1202
1289
  </div>
1203
- </div>
1290
+ </EjemploContenedor>
1204
1291
  </ITStack>
1205
1292
  }
1206
1293
  doc={{