@conatel-sa/react-ui 0.2.2 → 0.2.4

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.
package/README.md CHANGED
@@ -1,23 +1,23 @@
1
1
  # @conatel-sa/react-ui
2
2
 
3
- Biblioteca de componentes React para productos **Conatel** y **Vivion**. Mas de 20 componentes UI listos para usar, con soporte de theming por marca mediante CSS custom properties.
3
+ Biblioteca de componentes React para productos **Conatel** y **Vivion**. Más de 20 componentes UI listos para usar, con soporte de theming por marca mediante CSS custom properties. Export opcional de iconos (`./icons`).
4
4
 
5
- ## Instalacion
5
+ ## Instalación
6
6
 
7
7
  ```bash
8
8
  npm install @conatel-sa/react-ui
9
9
  ```
10
10
 
11
- ## Uso rapido
11
+ ## Uso rápido
12
12
 
13
- Importa el CSS de tokens **una sola vez** en el entry point de tu aplicacion:
13
+ Importá el CSS de tokens **una sola vez** en el entry point de tu aplicación:
14
14
 
15
15
  ```tsx
16
16
  // main.tsx
17
17
  import '@conatel-sa/react-ui/dist/index.css';
18
18
  ```
19
19
 
20
- Luego usa los componentes envueltos en un `ThemeProvider`:
20
+ Luego usá los componentes envueltos en un `ThemeProvider`:
21
21
 
22
22
  ```tsx
23
23
  import { ThemeProvider, Button, Card, Badge } from '@conatel-sa/react-ui';
@@ -36,12 +36,12 @@ function App() {
36
36
 
37
37
  ## Theming
38
38
 
39
- La libreria soporta dos temas de marca que se aplican a todos los componentes:
39
+ La librería soporta dos temas de marca que se aplican a todos los componentes:
40
40
 
41
41
  | Tema | Color primario | Uso |
42
42
  |---|---|---|
43
43
  | `conatel` | `#CC032E` | Productos Conatel |
44
- | `vivion` | `#009CDE` | Productos Vivion |
44
+ | `vivion` | `#0098D4` | Productos Vivion |
45
45
 
46
46
  ```tsx
47
47
  <ThemeProvider theme="vivion">
@@ -51,7 +51,7 @@ La libreria soporta dos temas de marca que se aplican a todos los componentes:
51
51
 
52
52
  ## Componentes disponibles
53
53
 
54
- ### Tipografia
54
+ ### Tipografía
55
55
  `Heading` - `Text`
56
56
 
57
57
  ### Formularios
@@ -63,29 +63,48 @@ La libreria soporta dos temas de marca que se aplican a todos los componentes:
63
63
  ### Contenedores
64
64
  `Card` - `CardHeader` - `CardBody` - `CardFooter` - `Modal`
65
65
 
66
- ### Navegacion
66
+ ### Navegación
67
67
  `Navbar` - `NavItem` - `Tabs` - `TabList` - `Tab` - `TabPanel`
68
68
 
69
69
  ### Datos
70
70
  `Table` - `TableHead` - `TableBody` - `TableRow` - `TableCell` - `TableHeaderCell`
71
71
 
72
- ### Miscelanea
73
- `Avatar` - `Divider` - `EmptyState` - `Button`
72
+ ### Miscelánea
73
+ `Avatar` - `Divider` - `EmptyState` - `Button` - `Sidebar` - `SidebarItem` - `Toast` - `ScoreSelector`
74
74
 
75
- ## TypeScript
75
+ ### Iconos (subpath `@conatel-sa/react-ui/icons`)
76
+
77
+ Material Symbols y envoltorio opcional para `lucide-react`:
78
+
79
+ ```tsx
80
+ import { Icon, IconProvider } from '@conatel-sa/react-ui/icons';
81
+ import '@conatel-sa/react-ui/dist/material-symbols.css';
82
+
83
+ function WithIcons() {
84
+ return (
85
+ <ThemeProvider theme="conatel">
86
+ <IconProvider injectStylesheet defaultSize="md">
87
+ <Icon name="search" size="md" />
88
+ </IconProvider>
89
+ </ThemeProvider>
90
+ );
91
+ }
92
+ ```
93
+
94
+ `lucide-react` es opcional (solo si usás `LucideIcon`).
76
95
 
77
- La libreria incluye tipos completos. No se requiere instalacion adicional de `@types`.
96
+ ## Subpaquetes opcionales
78
97
 
79
- ## Desarrollo
98
+ | Subpath | Contenido resumido |
99
+ |---------|---------------------|
100
+ | `@conatel-sa/react-ui/forms` | `PasswordInput`, `MultiSelectDropdown` |
101
+ | `@conatel-sa/react-ui/cards` | `ServiceCard`, `FeatureCard`, `ChangelogPanel`, `ArtifactReportCard` |
102
+ | `@conatel-sa/react-ui/dialogs` | `ChangelogDialog` (requiere `react-dom`) |
103
+ | `@conatel-sa/react-ui/metrics` | `StatInline`, `MiniMeter` |
104
+ | `@conatel-sa/react-ui/status` | `StatusSummaryPopover` |
80
105
 
81
- Todos los comandos corren dentro de contenedores Docker.
106
+ En las demos HTML, `library-gallery-new.html` carga `dist/forms.umd.js`, `cards.umd.js`, `dialogs.umd.js`, `metrics.umd.js`, `status.umd.js` (además de `icons.umd.js`) y fusiona los globales en `window.ReactLibrary`. Ver `docs/SUBPACKAGES.md` en el workspace react-ui.
82
107
 
83
- | Tarea | Comando |
84
- |---|---|
85
- | Build de la libreria | `docker compose run --rm app npm run build` |
86
- | Storybook | `docker compose up storybook` |
87
- | Dev server | `docker compose up` |
88
- | Lint | `docker compose run --rm app npm run lint` |
89
- | Tests | `docker compose run --rm app npm test` |
108
+ ## TypeScript
90
109
 
91
- El Storybook incluye un switcher interactivo para previsualizar todos los componentes en tema Conatel y Vivion.
110
+ La librería incluye tipos. No se requiere `@types` adicional para este paquete.
@@ -0,0 +1,37 @@
1
+ import type { CSSProperties, ReactNode } from 'react';
2
+
3
+ export type ServiceCardStatus = 'active' | 'degraded' | 'error' | 'info';
4
+ export type ServiceCardProps = {
5
+ icon?: string;
6
+ title: string;
7
+ description?: string;
8
+ status?: ServiceCardStatus;
9
+ count?: number;
10
+ onClick?: () => void;
11
+ };
12
+ export declare function ServiceCard(props: ServiceCardProps): JSX.Element;
13
+
14
+ export type FeatureCardProps = {
15
+ title: string;
16
+ description?: string;
17
+ icon?: string;
18
+ corner?: ReactNode;
19
+ href?: string;
20
+ onClick?: () => void;
21
+ children?: ReactNode;
22
+ style?: CSSProperties;
23
+ className?: string;
24
+ };
25
+ export declare function FeatureCard(props: FeatureCardProps): JSX.Element;
26
+
27
+ export type ChangelogItem = {
28
+ title: string;
29
+ content: ReactNode;
30
+ };
31
+ export type ChangelogPanelProps = { version?: string; items: ChangelogItem[] };
32
+ export declare function ChangelogPanel(props: ChangelogPanelProps): JSX.Element;
33
+
34
+ export type ArtifactStatVariant = 'primary' | 'success' | 'warning' | 'error' | 'info';
35
+ export type ArtifactStat = { label: string; value: number; variant?: ArtifactStatVariant; footer?: ReactNode };
36
+ export type ArtifactReportCardProps = { title?: string; stats: ArtifactStat[] };
37
+ export declare function ArtifactReportCard(props: ArtifactReportCardProps): JSX.Element;
package/dist/cards.mjs ADDED
@@ -0,0 +1,299 @@
1
+ // src/components/cards/ServiceCard.tsx
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ function statusStyles(status) {
4
+ switch (status) {
5
+ case "active":
6
+ return {
7
+ bg: "var(--color-success-light, rgba(16, 185, 129, 0.1))",
8
+ fg: "var(--color-success, #10b981)",
9
+ label: "OK"
10
+ };
11
+ case "degraded":
12
+ return {
13
+ bg: "var(--color-warning-light, rgba(245, 158, 11, 0.12))",
14
+ fg: "var(--color-warning, #f59e0b)",
15
+ label: "WARN"
16
+ };
17
+ case "error":
18
+ return {
19
+ bg: "var(--color-error-light, rgba(204, 3, 46, 0.12))",
20
+ fg: "var(--color-error, #CC032E)",
21
+ label: "ERROR"
22
+ };
23
+ case "info":
24
+ return {
25
+ bg: "var(--color-info-light, rgba(37, 99, 235, 0.12))",
26
+ fg: "var(--color-info, #2563eb)",
27
+ label: "INFO"
28
+ };
29
+ default:
30
+ return {
31
+ bg: "var(--color-neutral-100, #f5f5f5)",
32
+ fg: "var(--color-text-muted, #6b6b6b)",
33
+ label: "INFO"
34
+ };
35
+ }
36
+ }
37
+ function ServiceCard({
38
+ icon,
39
+ title,
40
+ description,
41
+ status,
42
+ count,
43
+ onClick
44
+ }) {
45
+ const st = statusStyles(status);
46
+ return /* @__PURE__ */ jsxs(
47
+ "div",
48
+ {
49
+ role: onClick ? "button" : void 0,
50
+ tabIndex: onClick ? 0 : void 0,
51
+ onClick,
52
+ onKeyDown: (e) => {
53
+ if (!onClick) return;
54
+ if (e.key === "Enter" || e.key === " ") onClick();
55
+ },
56
+ style: {
57
+ border: "1.5px solid var(--color-border, #e0e0e0)",
58
+ borderRadius: "var(--radius-lg, 8px)",
59
+ background: "var(--color-surface, #ffffff)",
60
+ boxShadow: "var(--shadow-sm, 0 1px 3px rgba(0,0,0,.1))",
61
+ padding: "var(--space-4, 16px)",
62
+ cursor: onClick ? "pointer" : "default"
63
+ },
64
+ children: [
65
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: "var(--space-3, 12px)" }, children: [
66
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "var(--space-3, 12px)", flex: 1, minWidth: 0 }, children: [
67
+ icon ? /* @__PURE__ */ jsx(
68
+ "span",
69
+ {
70
+ className: "material-symbols-outlined",
71
+ style: { fontSize: "1.5rem", color: "var(--color-primary, #CC032E)", marginTop: "2px" },
72
+ "aria-hidden": "true",
73
+ children: icon
74
+ }
75
+ ) : null,
76
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "var(--space-1, .25rem)", minWidth: 0 }, children: [
77
+ /* @__PURE__ */ jsx(
78
+ "div",
79
+ {
80
+ style: {
81
+ fontFamily: "var(--font-sans, system-ui)",
82
+ fontSize: "var(--text-base, 15px)",
83
+ fontWeight: "var(--weight-semibold, 600)",
84
+ color: "var(--color-text, #1a1a1a)",
85
+ whiteSpace: "nowrap",
86
+ overflow: "hidden",
87
+ textOverflow: "ellipsis"
88
+ },
89
+ children: title
90
+ }
91
+ ),
92
+ description ? /* @__PURE__ */ jsx("div", { style: { fontFamily: "var(--font-sans, system-ui)", fontSize: "var(--text-sm, 13px)", color: "var(--color-text-muted, #757578)", lineHeight: 1.3 }, children: description }) : null
93
+ ] })
94
+ ] }),
95
+ count != null ? /* @__PURE__ */ jsx(
96
+ "div",
97
+ {
98
+ style: {
99
+ minWidth: "3rem",
100
+ textAlign: "right",
101
+ fontFamily: "var(--font-sans, system-ui)",
102
+ fontSize: "var(--text-sm, 13px)",
103
+ color: "var(--color-text-muted, #757578)",
104
+ fontWeight: "var(--weight-medium, 500)"
105
+ },
106
+ children: count
107
+ }
108
+ ) : null
109
+ ] }),
110
+ status ? /* @__PURE__ */ jsx("div", { style: { marginTop: "var(--space-3, 12px)" }, children: /* @__PURE__ */ jsx(
111
+ "span",
112
+ {
113
+ style: {
114
+ display: "inline-flex",
115
+ alignItems: "center",
116
+ gap: "var(--space-2, 8px)",
117
+ padding: "var(--space-1, .25rem) var(--space-2, 8px)",
118
+ borderRadius: "var(--radius-full, 9999px)",
119
+ background: st.bg,
120
+ color: st.fg,
121
+ fontFamily: "var(--font-sans, system-ui)",
122
+ fontSize: "var(--text-sm, 13px)",
123
+ fontWeight: "var(--weight-medium, 500)",
124
+ whiteSpace: "nowrap"
125
+ },
126
+ children: st.label
127
+ }
128
+ ) }) : null
129
+ ]
130
+ }
131
+ );
132
+ }
133
+
134
+ // src/components/cards/FeatureCard.tsx
135
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
136
+ var baseCardStyle = {
137
+ position: "relative",
138
+ display: "block",
139
+ border: "1.5px solid var(--color-border, #e0e0e0)",
140
+ borderRadius: "var(--radius-lg, 12px)",
141
+ background: "var(--color-surface, #ffffff)",
142
+ boxShadow: "var(--shadow-sm, 0 1px 3px rgba(0,0,0,.08))",
143
+ padding: "var(--space-4, 16px)",
144
+ textDecoration: "none",
145
+ color: "inherit",
146
+ fontFamily: "var(--font-sans, system-ui)",
147
+ textAlign: "left",
148
+ cursor: "default",
149
+ boxSizing: "border-box"
150
+ };
151
+ function FeatureCard({
152
+ title,
153
+ description,
154
+ icon,
155
+ corner,
156
+ href,
157
+ onClick,
158
+ children,
159
+ style,
160
+ className
161
+ }) {
162
+ const interactive = Boolean(href || onClick);
163
+ const mergedStyle = {
164
+ ...baseCardStyle,
165
+ cursor: interactive ? "pointer" : "default",
166
+ ...style
167
+ };
168
+ const inner = /* @__PURE__ */ jsxs2(Fragment, { children: [
169
+ corner ? /* @__PURE__ */ jsx2(
170
+ "div",
171
+ {
172
+ style: {
173
+ position: "absolute",
174
+ top: "0.75rem",
175
+ right: "0.75rem",
176
+ display: "flex",
177
+ alignItems: "center",
178
+ gap: "0.25rem",
179
+ fontSize: "0.75rem",
180
+ color: "var(--color-text-muted, #757578)"
181
+ },
182
+ children: corner
183
+ }
184
+ ) : null,
185
+ icon ? /* @__PURE__ */ jsx2("div", { style: { marginBottom: "var(--space-3, 12px)" }, children: /* @__PURE__ */ jsx2("span", { className: "material-symbols-outlined", style: { fontSize: "2rem", color: "var(--color-primary, #2563eb)" }, "aria-hidden": true, children: icon }) }) : null,
186
+ /* @__PURE__ */ jsx2("div", { style: { fontWeight: 700, fontSize: "var(--text-base, 15px)", color: "var(--color-text, #1a1a1a)", marginBottom: "var(--space-2, 8px)" }, children: title }),
187
+ description ? /* @__PURE__ */ jsx2("div", { style: { fontSize: "var(--text-sm, 13px)", color: "var(--color-text-muted, #757578)", lineHeight: 1.45 }, children: description }) : null,
188
+ children
189
+ ] });
190
+ if (href) {
191
+ return /* @__PURE__ */ jsx2("a", { href, className, style: mergedStyle, children: inner });
192
+ }
193
+ if (onClick) {
194
+ return /* @__PURE__ */ jsx2("button", { type: "button", className, style: mergedStyle, onClick, children: inner });
195
+ }
196
+ return /* @__PURE__ */ jsx2("div", { className, style: mergedStyle, children: inner });
197
+ }
198
+
199
+ // src/components/cards/ChangelogPanel.tsx
200
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
201
+ function ChangelogPanel({ version, items }) {
202
+ return /* @__PURE__ */ jsxs3(
203
+ "div",
204
+ {
205
+ style: {
206
+ border: "1.5px solid var(--color-border, #e0e0e0)",
207
+ borderRadius: "var(--radius-lg, 8px)",
208
+ background: "var(--color-surface, #ffffff)",
209
+ boxShadow: "var(--shadow-sm, 0 1px 3px rgba(0,0,0,.1))",
210
+ padding: "var(--space-4, 16px)"
211
+ },
212
+ children: [
213
+ /* @__PURE__ */ jsx3("div", { style: { fontFamily: "var(--font-sans, system-ui)", fontWeight: "var(--weight-semibold, 600)", color: "var(--color-text, #1a1a1a)", fontSize: "var(--text-base, 15px)" }, children: version ? `Changelog ${version}` : "Changelog" }),
214
+ /* @__PURE__ */ jsx3("div", { style: { marginTop: "var(--space-3, 12px)", display: "flex", flexDirection: "column", gap: "var(--space-3, 12px)" }, children: items.map((it, idx) => /* @__PURE__ */ jsxs3("div", { children: [
215
+ /* @__PURE__ */ jsx3("div", { style: { fontFamily: "var(--font-sans, system-ui)", fontWeight: "var(--weight-semibold, 600)", color: "var(--color-text, #1a1a1a)", fontSize: "var(--text-sm, 13px)" }, children: it.title }),
216
+ /* @__PURE__ */ jsx3("div", { style: { fontFamily: "var(--font-sans, system-ui)", color: "var(--color-text-muted, #757578)", fontSize: "var(--text-sm, 13px)", lineHeight: 1.4, marginTop: "var(--space-1, .25rem)" }, children: it.content })
217
+ ] }, idx)) })
218
+ ]
219
+ }
220
+ );
221
+ }
222
+
223
+ // src/components/cards/ArtifactReportCard.tsx
224
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
225
+ function variantToColors(variant) {
226
+ switch (variant) {
227
+ case "success":
228
+ return { fg: "var(--color-success, #10b981)", bg: "var(--color-success, #10b981)" };
229
+ case "warning":
230
+ return { fg: "var(--color-warning, #f59e0b)", bg: "var(--color-warning, #f59e0b)" };
231
+ case "error":
232
+ return { fg: "var(--color-error, #CC032E)", bg: "var(--color-error, #CC032E)" };
233
+ case "info":
234
+ return { fg: "var(--color-info, #2563eb)", bg: "var(--color-info, #2563eb)" };
235
+ case "primary":
236
+ default:
237
+ return { fg: "var(--color-primary, var(--color-brand, #CC032E))", bg: "var(--color-primary, var(--color-brand, #CC032E))" };
238
+ }
239
+ }
240
+ function ArtifactReportCard({ title, stats }) {
241
+ const max = Math.max(1, ...stats.map((s) => typeof s.value === "number" ? s.value : 0));
242
+ return /* @__PURE__ */ jsxs4(
243
+ "div",
244
+ {
245
+ style: {
246
+ border: "1.5px solid var(--color-border, #e0e0e0)",
247
+ borderRadius: "var(--radius-lg, 8px)",
248
+ background: "var(--color-surface, #ffffff)",
249
+ boxShadow: "var(--shadow-sm, 0 1px 3px rgba(0,0,0,.1))",
250
+ padding: "var(--space-4, 16px)"
251
+ },
252
+ children: [
253
+ title ? /* @__PURE__ */ jsx4("div", { style: { fontFamily: "var(--font-sans, system-ui)", fontWeight: "var(--weight-semibold, 600)", color: "var(--color-text, #1a1a1a)", fontSize: "var(--text-base, 15px)" }, children: title }) : null,
254
+ /* @__PURE__ */ jsx4("div", { style: { marginTop: "var(--space-3, 12px)", display: "flex", flexDirection: "column", gap: "var(--space-3, 12px)" }, children: stats.map((s, idx) => {
255
+ const colors = variantToColors(s.variant);
256
+ const ratio = Math.max(0, Math.min(1, s.value / max));
257
+ return /* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", gap: "var(--space-2, 8px)" }, children: [
258
+ /* @__PURE__ */ jsxs4("div", { style: { display: "flex", justifyContent: "space-between", gap: "var(--space-2, 8px)" }, children: [
259
+ /* @__PURE__ */ jsx4("div", { style: { fontFamily: "var(--font-sans, system-ui)", color: "var(--color-text-muted, #757578)", fontSize: "var(--text-sm, 13px)", fontWeight: "var(--weight-medium, 500)" }, children: s.label }),
260
+ /* @__PURE__ */ jsx4("div", { style: { fontFamily: "var(--font-sans, system-ui)", color: colors.fg, fontSize: "var(--text-sm, 13px)", fontWeight: "var(--weight-semibold, 600)" }, children: s.value })
261
+ ] }),
262
+ /* @__PURE__ */ jsx4(
263
+ "div",
264
+ {
265
+ style: {
266
+ width: "100%",
267
+ height: "10px",
268
+ borderRadius: "var(--radius-full, 9999px)",
269
+ background: "var(--color-neutral-200, rgba(0,0,0,.08))",
270
+ overflow: "hidden"
271
+ },
272
+ "aria-hidden": "true",
273
+ children: /* @__PURE__ */ jsx4(
274
+ "div",
275
+ {
276
+ style: {
277
+ width: `${Math.round(ratio * 100)}%`,
278
+ height: "100%",
279
+ background: colors.bg,
280
+ borderRadius: "inherit",
281
+ transition: "width var(--duration-base, .15s) var(--ease-out, ease) "
282
+ }
283
+ }
284
+ )
285
+ }
286
+ ),
287
+ s.footer ? /* @__PURE__ */ jsx4("div", { style: { fontFamily: "var(--font-sans, system-ui)", color: "var(--color-text-muted, #757578)", fontSize: "var(--text-sm, 13px)", lineHeight: 1.35 }, children: s.footer }) : null
288
+ ] }, idx);
289
+ }) })
290
+ ]
291
+ }
292
+ );
293
+ }
294
+ export {
295
+ ArtifactReportCard,
296
+ ChangelogPanel,
297
+ FeatureCard,
298
+ ServiceCard
299
+ };