@mimi-ng/cli 0.1.1 → 0.3.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 (104) hide show
  1. package/README.md +28 -1
  2. package/dist/init/css.js +17 -0
  3. package/dist/init/index.js +7 -5
  4. package/dist/init/items.js +9 -0
  5. package/dist/registry.json +482 -1
  6. package/dist/templates/components/avatar/avatar.ts +1 -1
  7. package/dist/templates/components/avatar/avatar.variants.ts +4 -4
  8. package/dist/templates/components/badge/badge.ts +41 -6
  9. package/dist/templates/components/badge/badge.variants.ts +105 -11
  10. package/dist/templates/components/button/button.ts +74 -7
  11. package/dist/templates/components/button/button.variants.ts +145 -21
  12. package/dist/templates/components/calendar/calendar-texts.ts +72 -0
  13. package/dist/templates/components/calendar/calendar.ts +588 -0
  14. package/dist/templates/components/calendar/dates.ts +181 -0
  15. package/dist/templates/components/calendar/index.ts +3 -0
  16. package/dist/templates/components/card/card.ts +8 -5
  17. package/dist/templates/components/checkbox/checkbox.ts +3 -3
  18. package/dist/templates/components/chip/chip-texts.ts +40 -0
  19. package/dist/templates/components/chip/chip.ts +116 -0
  20. package/dist/templates/components/chip/index.ts +2 -0
  21. package/dist/templates/components/color-picker/color-picker-texts.ts +57 -0
  22. package/dist/templates/components/color-picker/color-picker.ts +718 -0
  23. package/dist/templates/components/color-picker/color.ts +157 -0
  24. package/dist/templates/components/color-picker/index.ts +3 -0
  25. package/dist/templates/components/combobox/combobox-texts.ts +70 -0
  26. package/dist/templates/components/combobox/combobox.ts +798 -0
  27. package/dist/templates/components/combobox/index.ts +2 -0
  28. package/dist/templates/components/confirm/confirm-texts.ts +46 -0
  29. package/dist/templates/components/confirm/confirm.ts +190 -0
  30. package/dist/templates/components/confirm/index.ts +2 -0
  31. package/dist/templates/components/context-menu/context-menu.ts +378 -0
  32. package/dist/templates/components/context-menu/index.ts +14 -0
  33. package/dist/templates/components/date-picker/date-picker.ts +240 -0
  34. package/dist/templates/components/date-picker/index.ts +3 -0
  35. package/dist/templates/components/date-range/date-range.ts +308 -0
  36. package/dist/templates/components/date-range/index.ts +1 -0
  37. package/dist/templates/components/dialog/dialog-texts.ts +41 -0
  38. package/dist/templates/components/dialog/dialog.ts +701 -0
  39. package/dist/templates/components/dialog/index.ts +18 -0
  40. package/dist/templates/components/dropdown-menu/dropdown-menu.ts +252 -0
  41. package/dist/templates/components/dropdown-menu/index.ts +14 -0
  42. package/dist/templates/components/file-upload/file-upload-texts.ts +77 -0
  43. package/dist/templates/components/file-upload/file-upload.ts +698 -0
  44. package/dist/templates/components/file-upload/index.ts +2 -0
  45. package/dist/templates/components/form-field/form-error.ts +1 -1
  46. package/dist/templates/components/form-field/form-field.ts +3 -2
  47. package/dist/templates/components/input/input.variants.ts +6 -4
  48. package/dist/templates/components/input-mask/index.ts +1 -0
  49. package/dist/templates/components/input-mask/input-mask.ts +319 -0
  50. package/dist/templates/components/input-otp/index.ts +1 -0
  51. package/dist/templates/components/input-otp/input-otp.ts +212 -0
  52. package/dist/templates/components/menu/index.ts +15 -0
  53. package/dist/templates/components/menu/menu.ts +656 -0
  54. package/dist/templates/components/number-input/index.ts +2 -0
  55. package/dist/templates/components/number-input/number-input-texts.ts +46 -0
  56. package/dist/templates/components/number-input/number-input.ts +450 -0
  57. package/dist/templates/components/option-list/index.ts +11 -0
  58. package/dist/templates/components/option-list/option-list.ts +518 -0
  59. package/dist/templates/components/pagination/index.ts +2 -0
  60. package/dist/templates/components/pagination/pagination-page-size.ts +74 -0
  61. package/dist/templates/components/pagination/pagination-texts.ts +69 -0
  62. package/dist/templates/components/pagination/pagination.ts +443 -0
  63. package/dist/templates/components/password/index.ts +2 -0
  64. package/dist/templates/components/password/password-texts.ts +68 -0
  65. package/dist/templates/components/password/password.ts +363 -0
  66. package/dist/templates/components/popover/index.ts +12 -0
  67. package/dist/templates/components/popover/popover.ts +407 -0
  68. package/dist/templates/components/progress/index.ts +1 -0
  69. package/dist/templates/components/progress/progress.ts +217 -0
  70. package/dist/templates/components/select/index.ts +12 -0
  71. package/dist/templates/components/select/select-texts.ts +62 -0
  72. package/dist/templates/components/select/select.ts +1086 -0
  73. package/dist/templates/components/separator/separator.variants.ts +10 -7
  74. package/dist/templates/components/skeleton/skeleton.ts +4 -1
  75. package/dist/templates/components/slider/index.ts +2 -0
  76. package/dist/templates/components/slider/slider-texts.ts +26 -0
  77. package/dist/templates/components/slider/slider.ts +425 -0
  78. package/dist/templates/components/switch/switch.ts +6 -6
  79. package/dist/templates/components/tabs/index.ts +2 -0
  80. package/dist/templates/components/tabs/tabs.ts +426 -0
  81. package/dist/templates/components/tags-input/index.ts +2 -0
  82. package/dist/templates/components/tags-input/tags-input-texts.ts +44 -0
  83. package/dist/templates/components/tags-input/tags-input.ts +303 -0
  84. package/dist/templates/components/textarea/textarea.variants.ts +14 -11
  85. package/dist/templates/components/toast/index.ts +3 -0
  86. package/dist/templates/components/toast/toast-config.ts +45 -0
  87. package/dist/templates/components/toast/toast-texts.ts +46 -0
  88. package/dist/templates/components/toast/toast.ts +1000 -0
  89. package/dist/templates/components/toggle-group/index.ts +1 -0
  90. package/dist/templates/components/toggle-group/toggle-group.ts +406 -0
  91. package/dist/templates/components/toolbar/index.ts +1 -0
  92. package/dist/templates/components/toolbar/toolbar.ts +377 -0
  93. package/dist/templates/components/tooltip/index.ts +7 -0
  94. package/dist/templates/components/tooltip/tooltip.ts +407 -0
  95. package/dist/templates/theme/provider.ts +75 -6
  96. package/dist/templates/theme/theme-base.css +410 -9
  97. package/dist/templates/theme/types.ts +494 -4
  98. package/dist/templates/utils/cn.ts +15 -1
  99. package/dist/templates/utils/control-styles.ts +2 -2
  100. package/dist/templates/utils/overlay.ts +153 -0
  101. package/dist/ui/index.js +184 -8
  102. package/dist/ui/schema.json +100 -0
  103. package/dist/utils/write-files.js +166 -59
  104. package/package.json +1 -1
@@ -0,0 +1,153 @@
1
+ import type { ConnectedPosition } from '@angular/cdk/overlay';
2
+
3
+ /*
4
+ * Posición, flecha y animación compartidas por los overlays de Mimi (Popover, Tooltip…). Usa
5
+ * tipos de @angular/cdk/overlay: impórtalo siempre con su archivo concreto
6
+ * (`@/components/ui/utils/overlay`), nunca desde el índice de utils, que no lo reexporta para no
7
+ * arrastrar el CDK a quien no lo usa.
8
+ */
9
+
10
+ export type MimiOverlaySide = 'top' | 'right' | 'bottom' | 'left';
11
+ export type MimiOverlayAlign = 'start' | 'center' | 'end';
12
+
13
+ /** Distancia mínima de un overlay al borde de la pantalla (no está en el diseño: spec 13, plan D6). */
14
+ export const MIMI_VIEWPORT_MARGIN = 8;
15
+
16
+ const OPPOSITE: Record<MimiOverlaySide, MimiOverlaySide> = {
17
+ top: 'bottom',
18
+ bottom: 'top',
19
+ left: 'right',
20
+ right: 'left',
21
+ };
22
+
23
+ function connectedPosition(
24
+ side: MimiOverlaySide,
25
+ align: MimiOverlayAlign,
26
+ offset: number,
27
+ ): ConnectedPosition {
28
+ if (side === 'top' || side === 'bottom') {
29
+ return side === 'bottom'
30
+ ? { originX: align, originY: 'bottom', overlayX: align, overlayY: 'top', offsetY: offset }
31
+ : { originX: align, originY: 'top', overlayX: align, overlayY: 'bottom', offsetY: -offset };
32
+ }
33
+ const y = align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center';
34
+ return side === 'right'
35
+ ? { originX: 'end', originY: y, overlayX: 'start', overlayY: y, offsetX: offset }
36
+ : { originX: 'start', originY: y, overlayX: 'end', overlayY: y, offsetX: -offset };
37
+ }
38
+
39
+ /** Las otras alineaciones, en orden de preferencia (la opuesta antes que el centro). */
40
+ const FALLBACK_ALIGNS: Record<MimiOverlayAlign, MimiOverlayAlign[]> = {
41
+ start: ['end', 'center'],
42
+ end: ['start', 'center'],
43
+ center: ['start', 'end'],
44
+ };
45
+
46
+ /**
47
+ * Posiciones para el CDK, en orden de preferencia: el lado pedido con la alineación pedida y
48
+ * después con las otras dos; el lado opuesto, igual; y, por último, los otros dos lados
49
+ * centrados. `offset` es la separación con el trigger.
50
+ *
51
+ * Las otras alineaciones del mismo lado (5.17a) evitan que en una pantalla chica el panel se
52
+ * salga por un costado: en 360px, un menú de 240px alineado al inicio de un trigger cercano al
53
+ * borde derecho no cabía en ninguna de las cuatro posiciones de antes y el CDK lo dejaba fuera.
54
+ */
55
+ export function mimiConnectedPositions(
56
+ side: MimiOverlaySide,
57
+ align: MimiOverlayAlign,
58
+ offset: number,
59
+ ): ConnectedPosition[] {
60
+ const others: MimiOverlaySide[] =
61
+ side === 'top' || side === 'bottom' ? ['right', 'left'] : ['bottom', 'top'];
62
+ const aligns = [align, ...FALLBACK_ALIGNS[align]];
63
+ return [
64
+ ...aligns.map((a) => connectedPosition(side, a, offset)),
65
+ ...aligns.map((a) => connectedPosition(OPPOSITE[side], a, offset)),
66
+ ...others.map((other) => connectedPosition(other, 'center', offset)),
67
+ ];
68
+ }
69
+
70
+ /**
71
+ * Posiciones para abrir en un punto (el puntero, en Context Menu): la esquina superior izquierda
72
+ * del panel en el punto; si no cabe, se voltea a la izquierda del punto, hacia arriba o ambas.
73
+ */
74
+ export function mimiPointPositions(): ConnectedPosition[] {
75
+ return [
76
+ { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'top' },
77
+ { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'top' },
78
+ { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' },
79
+ { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'bottom' },
80
+ ];
81
+ }
82
+
83
+ /** Lado en el que quedó el overlay, según la posición que eligió el CDK. */
84
+ export function mimiPlacedSide({
85
+ originX,
86
+ originY,
87
+ overlayX,
88
+ overlayY,
89
+ }: ConnectedPosition): MimiOverlaySide {
90
+ if (originY === 'bottom' && overlayY === 'top') return 'bottom';
91
+ if (originY === 'top' && overlayY === 'bottom') return 'top';
92
+ return originX === 'end' && overlayX === 'start' ? 'right' : 'left';
93
+ }
94
+
95
+ /**
96
+ * Dónde va la flecha para que apunte al centro del trigger: distancia desde el borde del panel
97
+ * (izquierdo arriba/abajo, superior a los lados), dentro del panel. null si aún no hay medidas.
98
+ */
99
+ export function mimiArrowOffset(
100
+ trigger: DOMRect,
101
+ panel: DOMRect,
102
+ side: MimiOverlaySide,
103
+ ): string | null {
104
+ if (panel.width === 0 || panel.height === 0) return null;
105
+ const vertical = side === 'top' || side === 'bottom';
106
+ const offset = vertical
107
+ ? trigger.left + trigger.width / 2 - panel.left
108
+ : trigger.top + trigger.height / 2 - panel.top;
109
+ const size = vertical ? panel.width : panel.height;
110
+ return `${Math.min(Math.max(offset, 0), size)}px`;
111
+ }
112
+
113
+ /**
114
+ * Entrada y salida de los overlays, para el `styles` del componente. Valores de
115
+ * --mimi-transition (spec 6.6): 0.15s cubic-bezier(.2,.8,.2,1), escala desde --mimi-press-scale.
116
+ * Sin animación con movimiento reducido. El panel lleva `data-mimi-overlay-panel` y `data-state`.
117
+ */
118
+ export const MIMI_OVERLAY_ANIMATION = `
119
+ @keyframes mimi-overlay-in {
120
+ from {
121
+ opacity: 0;
122
+ scale: var(--mimi-press-scale);
123
+ }
124
+ }
125
+ @keyframes mimi-overlay-out {
126
+ to {
127
+ opacity: 0;
128
+ scale: var(--mimi-press-scale);
129
+ }
130
+ }
131
+ [data-mimi-overlay-panel][data-state='open'] {
132
+ animation: mimi-overlay-in 0.15s cubic-bezier(0.2, 0.8, 0.2, 1);
133
+ }
134
+ [data-mimi-overlay-panel][data-state='closed'] {
135
+ animation: mimi-overlay-out 0.15s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
136
+ }
137
+ @media (prefers-reduced-motion: reduce) {
138
+ [data-mimi-overlay-panel] {
139
+ animation: none !important;
140
+ }
141
+ }
142
+ `;
143
+
144
+ /**
145
+ * Se resuelve cuando terminan las animaciones del elemento (la de salida). Sin animaciones
146
+ * (movimiento reducido, o un entorno sin Web Animations), enseguida.
147
+ */
148
+ export function mimiWaitForExit(element: HTMLElement | undefined): Promise<void> {
149
+ const animations = element?.getAnimations?.() ?? [];
150
+ return Promise.allSettled(animations.map((animation) => animation.finished)).then(
151
+ () => undefined,
152
+ );
153
+ }
package/dist/ui/index.js CHANGED
@@ -4,6 +4,8 @@ exports.AVAILABLE = void 0;
4
4
  exports.ui = ui;
5
5
  const schematics_1 = require("@angular-devkit/schematics");
6
6
  const utility_1 = require("@schematics/angular/utility");
7
+ const css_1 = require("../init/css");
8
+ const items_1 = require("../init/items");
7
9
  const paths_1 = require("../init/paths");
8
10
  const registry_1 = require("../registry");
9
11
  const project_1 = require("../utils/project");
@@ -17,8 +19,10 @@ exports.AVAILABLE = Object.entries(registry_1.registry.items)
17
19
  * `ng g mimi button input form-field`: copia los componentes y sus dependencias del registro a la
18
20
  * carpeta de mimi.json. Sin nombres, pregunta (x-prompt de selección múltiple).
19
21
  *
20
- * Requiere init (mimi.json). Archivos existentes: igual → nada; distinto → se omite con aviso;
21
- * --overwrite → se reemplaza. Guarda la copia original en .mimi/base/ y la versión de cada
22
+ * Requiere init (mimi.json). Revisa también el tema y lo que copia init, y lo actualiza si el
23
+ * usuario no lo modificó. Todo o nada por componente (ver writeTemplates): si el usuario modificó
24
+ * un archivo de una versión anterior, ese componente y los que dependen de él no se tocan, con
25
+ * un aviso; --overwrite reemplaza. Guarda la copia original en .mimi/base/ y la versión de cada
22
26
  * componente en mimi.json. Instala las dependencias que falten con el gestor del proyecto.
23
27
  */
24
28
  function ui(options) {
@@ -27,13 +31,15 @@ function ui(options) {
27
31
  const report = (0, write_files_1.emptyReport)();
28
32
  return (0, schematics_1.chain)([
29
33
  (0, write_files_1.writeTemplates)({
30
- files: plan.items.flatMap((item) => registry_1.registry.items[item].files),
34
+ items: [...plan.items, ...plan.implicit],
35
+ implicit: plan.implicit,
31
36
  componentsDir: plan.componentsDir,
32
37
  overwrite: options.overwrite ?? false,
33
38
  version: registry_1.registry.version,
34
39
  report,
35
40
  }),
36
41
  updateMimiConfig(plan, report),
42
+ updateGlobalCss(plan),
37
43
  ...Object.entries(plan.newPackages).map(([name, version]) => (0, utility_1.addDependency)(name, version, {
38
44
  type: utility_1.DependencyType.Default,
39
45
  existing: utility_1.ExistingBehavior.Skip,
@@ -82,11 +88,134 @@ function inspect(tree, options) {
82
88
  for (const [name, version] of Object.entries(registry_1.registry.items[item].peerDependencies ?? {})) {
83
89
  if (installed[name])
84
90
  continue;
85
- newPackages[name] = name.startsWith('@angular/') && angularRange ? angularRange : version;
91
+ newPackages[name] =
92
+ name === '@angular/aria'
93
+ ? ariaVersion(tree, installed, version)
94
+ : name.startsWith('@angular/') && angularRange
95
+ ? angularRange
96
+ : version;
86
97
  }
87
98
  }
99
+ // aria necesita el cdk (bidi, a11y, platform). Un ítem que solo importa aria (Tabs) no declara
100
+ // el cdk como peer; sin otro ítem que lo traiga, va con la misma versión que aria.
101
+ if (newPackages['@angular/aria'] && !installed['@angular/cdk'] && !newPackages['@angular/cdk']) {
102
+ newPackages['@angular/cdk'] = newPackages['@angular/aria'];
103
+ }
104
+ const implicit = [...new Set(items_1.INIT_ITEMS.flatMap((item) => (0, registry_1.resolveItems)(item)))].filter((item) => !items.includes(item));
88
105
  const componentsDir = (0, paths_1.normalizePath)(config.aliases?.components ?? 'src/app/components/ui');
89
- return { componentsDir, config, items, newPackages };
106
+ const outdated = outdatedPeers(tree, items, installed, newPackages);
107
+ const updatable = PEERS_WITH_MINIMUM.filter((name) => installed[name] || newPackages[name]);
108
+ return { componentsDir, config, items, implicit, newPackages, outdated, updatable };
109
+ }
110
+ // ── Versiones mínimas de cdk y aria (M.4) ─────────────────────────────────────────────
111
+ /**
112
+ * Paquetes cuya versión mínima se vigila. La CLI no los cambia si el proyecto ya los tiene (se
113
+ * actualizan con `ng update`, junto con el resto de Angular), pero avisa si quedan por debajo de
114
+ * lo que pide el registro: con aria y cdk 22.2.3, Combobox y Select lanzan NG0950 (spec 4,
115
+ * «#33974»).
116
+ */
117
+ const PEERS_WITH_MINIMUM = ['@angular/cdk', '@angular/aria'];
118
+ const RANGE = /^\s*(\^|~|>=|=)?\s*v?(\d+)\.(\d+)\.(\d+)\s*$/;
119
+ function parseRange(range) {
120
+ const match = RANGE.exec(range);
121
+ if (!match)
122
+ return null;
123
+ return { op: match[1] ?? '=', version: [+match[2], +match[3], +match[4]] };
124
+ }
125
+ function compare(a, b) {
126
+ return a[0] - b[0] || a[1] - b[1] || a[2] - b[2];
127
+ }
128
+ /**
129
+ * Si un rango puede instalar `required` o una posterior. Lo que no se entiende (`*`, `latest`,
130
+ * `22.2.x`, `workspace:`…) cuenta como que sí: el aviso no da falsas alarmas.
131
+ */
132
+ function canReach(range, required) {
133
+ const parsed = parseRange(range);
134
+ if (!parsed)
135
+ return true;
136
+ if (parsed.op === '>=' || compare(parsed.version, required) >= 0)
137
+ return true;
138
+ // Por debajo del mínimo: llega solo si el tope del rango (exclusivo) queda por encima.
139
+ const [major, minor, patch] = parsed.version;
140
+ const upper = parsed.op === '^'
141
+ ? major > 0
142
+ ? [major + 1, 0, 0]
143
+ : minor > 0
144
+ ? [0, minor + 1, 0]
145
+ : [0, 0, patch + 1]
146
+ : parsed.op === '~'
147
+ ? [major, minor + 1, 0]
148
+ : null;
149
+ return upper !== null && compare(required, upper) < 0;
150
+ }
151
+ /** El mínimo que piden los ítems para cada paquete vigilado (aria implica el mismo cdk). */
152
+ function requiredMinimums(items) {
153
+ const minimums = new Map();
154
+ for (const item of items) {
155
+ const { dependencies = {}, peerDependencies = {} } = registry_1.registry.items[item];
156
+ for (const [name, range] of Object.entries({ ...dependencies, ...peerDependencies })) {
157
+ if (!PEERS_WITH_MINIMUM.includes(name))
158
+ continue;
159
+ const version = parseRange(range)?.version;
160
+ if (!version)
161
+ continue;
162
+ const names = name === '@angular/aria' ? [name, '@angular/cdk'] : [name];
163
+ for (const target of names) {
164
+ const known = minimums.get(target);
165
+ if (!known || compare(version, known) > 0)
166
+ minimums.set(target, version);
167
+ }
168
+ }
169
+ }
170
+ return minimums;
171
+ }
172
+ function outdatedPeers(tree, items, installed, newPackages) {
173
+ const outdated = [];
174
+ for (const [name, required] of requiredMinimums(items)) {
175
+ const declared = installed[name] ?? newPackages[name];
176
+ if (!declared)
177
+ continue;
178
+ // Si ya está instalado, manda la versión de node_modules (la que corre de verdad).
179
+ const onDisk = installed[name] ? installedVersion(tree, name) : null;
180
+ const version = onDisk ? parseRange(onDisk)?.version : null;
181
+ const ok = version ? compare(version, required) >= 0 : canReach(declared, required);
182
+ if (!ok) {
183
+ outdated.push({
184
+ name,
185
+ current: onDisk ?? declared,
186
+ source: onDisk ? 'installed' : installed[name] ? 'declared' : 'added',
187
+ required: required.join('.'),
188
+ });
189
+ }
190
+ }
191
+ return outdated.sort((a, b) => a.name.localeCompare(b.name));
192
+ }
193
+ const SOURCE_TEXT = {
194
+ installed: (current) => `${current} instalada`,
195
+ declared: (current) => `"${current}" en package.json`,
196
+ added: (current) => `"${current}", que se agrega ahora`,
197
+ };
198
+ function installedVersion(tree, name) {
199
+ const file = tree.read(`node_modules/${name}/package.json`);
200
+ if (!file)
201
+ return null;
202
+ const { version } = JSON.parse(file.toString('utf-8'));
203
+ return version ?? null;
204
+ }
205
+ /**
206
+ * @angular/aria pide como peer la versión exacta de @angular/cdk (22.1.7 → cdk 22.1.7). Si el cdk
207
+ * está instalado, aria va en esa versión (de `node_modules`, que el árbol del schematic lee del
208
+ * disco); si está declarado pero sin instalar, con su mismo rango; si no hay cdk, con el rango de
209
+ * `@angular/core`, igual que el cdk que se agrega junto con él (lo declare otro ítem o no).
210
+ */
211
+ function ariaVersion(tree, installed, fallback) {
212
+ const cdk = tree.read('node_modules/@angular/cdk/package.json');
213
+ if (cdk) {
214
+ const { version } = JSON.parse(cdk.toString('utf-8'));
215
+ if (version)
216
+ return version;
217
+ }
218
+ return installed['@angular/cdk'] ?? installed['@angular/core'] ?? fallback;
90
219
  }
91
220
  /** El componente más parecido (distancia de edición ≤ 2, o que empiece igual). */
92
221
  function closest(name) {
@@ -115,15 +244,19 @@ function editDistance(a, b) {
115
244
  // ── mimi.json ─────────────────────────────────────────────────────────────────────────
116
245
  /**
117
246
  * Registra la versión de cada componente cuyos archivos quedaron iguales a la plantilla. Si
118
- * alguno se omitió por estar modificado, se conserva lo que había.
247
+ * alguno se omitió por estar modificado, o el componente no se escribió (bloqueado), se conserva
248
+ * lo que había (y uno que no se agregó no aparece).
119
249
  */
120
250
  function updateMimiConfig(plan, report) {
121
251
  return (tree) => {
122
252
  const skipped = new Set(report.skipped);
253
+ const blocked = new Set(report.blocked.map((b) => b.item));
123
254
  const components = { ...plan.config.components };
124
255
  for (const item of plan.items) {
125
256
  if (registry_1.registry.items[item].type !== 'component')
126
257
  continue;
258
+ if (blocked.has(item))
259
+ continue;
127
260
  if (registry_1.registry.items[item].files.some((file) => skipped.has(file)))
128
261
  continue;
129
262
  components[item] = { version: registry_1.registry.version };
@@ -134,6 +267,38 @@ function updateMimiConfig(plan, report) {
134
267
  tree.overwrite('mimi.json', text);
135
268
  };
136
269
  }
270
+ // ── CSS global ────────────────────────────────────────────────────────────────────────
271
+ /**
272
+ * Agrega los `cssImports` de los ítems (p. ej. `@angular/cdk/overlay-prebuilt.css`, que pide la
273
+ * guía del CDK) al CSS global de mimi.json, una sola vez. Van después del `@import` del tema (o
274
+ * del de Tailwind): los `@import` tienen que ir antes que cualquier otra regla, y así quedan
275
+ * junto a los de Mimi. Si no se encuentra el archivo, se explica cómo agregarlos a mano.
276
+ */
277
+ function updateGlobalCss(plan) {
278
+ return (tree, context) => {
279
+ const imports = [
280
+ ...new Set(plan.items.flatMap((item) => registry_1.registry.items[item].cssImports ?? [])),
281
+ ];
282
+ if (imports.length === 0)
283
+ return;
284
+ const cssPath = plan.config.tailwind?.css;
285
+ const css = cssPath && tree.exists(cssPath) ? tree.readText(cssPath) : null;
286
+ const missing = imports.filter((path) => !css || !(0, css_1.hasDirective)(css, '@import', path));
287
+ if (missing.length === 0)
288
+ return;
289
+ const lines = missing.map((path) => `@import "${path}";`);
290
+ const updated = css === null ? null : (0, css_1.insertAfterTheme)(css, lines);
291
+ if (!cssPath || updated === null) {
292
+ context.logger.warn(`No se encontró el CSS global${cssPath ? ` (${cssPath})` : ''} con el @import de ` +
293
+ `Tailwind. Agrega a mano, después del tema de Mimi:\n${lines.map((l) => ` ${l}`).join('\n')}`);
294
+ return;
295
+ }
296
+ tree.overwrite(cssPath, updated);
297
+ context.logger.info(`Agregado a ${cssPath}:`);
298
+ for (const line of lines)
299
+ context.logger.info(` ${line}`);
300
+ };
301
+ }
137
302
  // ── Mensaje final ─────────────────────────────────────────────────────────────────────
138
303
  function summary(plan, report) {
139
304
  return (_tree, context) => {
@@ -149,13 +314,17 @@ function summary(plan, report) {
149
314
  for (const file of report.overwritten)
150
315
  log.info(` ~ ${path(file)}`);
151
316
  }
152
- const itemOf = (file) => plan.items.find((item) => registry_1.registry.items[item].files.includes(file)) ?? file;
317
+ const itemOf = (file) => [...plan.items, ...plan.implicit].find((item) => registry_1.registry.items[item].files.includes(file)) ??
318
+ file;
153
319
  for (const message of (0, write_files_1.updatedMessages)(report, itemOf, registry_1.registry.version))
154
320
  log.info(message);
155
321
  for (const file of report.skipped) {
156
322
  log.warn(`Omitido: ${path(file)} ya existe con otro contenido (usa --overwrite para reemplazarlo).`);
157
323
  }
158
- if (!(0, write_files_1.hasFileChanges)(report) && report.skipped.length === 0) {
324
+ for (const message of (0, write_files_1.blockedMessages)(report, plan.componentsDir, registry_1.registry.version)) {
325
+ log.warn(message);
326
+ }
327
+ if (!(0, write_files_1.hasFileChanges)(report) && report.skipped.length === 0 && report.blocked.length === 0) {
159
328
  log.info('Nada que hacer: los archivos ya están al día.');
160
329
  }
161
330
  const packages = Object.entries(plan.newPackages);
@@ -164,6 +333,13 @@ function summary(plan, report) {
164
333
  for (const [name, version] of packages)
165
334
  log.info(` ${name}@${version}`);
166
335
  }
336
+ if (plan.outdated.length > 0) {
337
+ const required = [...new Set(plan.outdated.map((peer) => peer.required))].join(', ');
338
+ const lines = plan.outdated.map((peer) => ` ${peer.name}: ${SOURCE_TEXT[peer.source](peer.current)}`);
339
+ log.warn(`Mimi necesita @angular/cdk y @angular/aria ${required} o posterior (las anteriores ` +
340
+ `tienen errores conocidos con sus componentes) y tu proyecto tiene:\n${lines.join('\n')}\n` +
341
+ `Actualízalos con:\n ng update ${plan.updatable.join(' ')}`);
342
+ }
167
343
  if ((0, write_files_1.hasFileChanges)(report)) {
168
344
  log.info(`Guarda la carpeta ${write_files_1.BASE_DIR.split('/')[0]}/ en git: Mimi la usa para actualizar tus ` +
169
345
  'componentes sin perder tus cambios.');
@@ -31,6 +31,10 @@
31
31
  "value": "button",
32
32
  "label": "button"
33
33
  },
34
+ {
35
+ "value": "calendar",
36
+ "label": "calendar"
37
+ },
34
38
  {
35
39
  "value": "card",
36
40
  "label": "card"
@@ -39,6 +43,42 @@
39
43
  "value": "checkbox",
40
44
  "label": "checkbox"
41
45
  },
46
+ {
47
+ "value": "color-picker",
48
+ "label": "color-picker"
49
+ },
50
+ {
51
+ "value": "combobox",
52
+ "label": "combobox"
53
+ },
54
+ {
55
+ "value": "confirm",
56
+ "label": "confirm"
57
+ },
58
+ {
59
+ "value": "context-menu",
60
+ "label": "context-menu"
61
+ },
62
+ {
63
+ "value": "date-picker",
64
+ "label": "date-picker"
65
+ },
66
+ {
67
+ "value": "date-range",
68
+ "label": "date-range"
69
+ },
70
+ {
71
+ "value": "dialog",
72
+ "label": "dialog"
73
+ },
74
+ {
75
+ "value": "dropdown-menu",
76
+ "label": "dropdown-menu"
77
+ },
78
+ {
79
+ "value": "file-upload",
80
+ "label": "file-upload"
81
+ },
42
82
  {
43
83
  "value": "form-field",
44
84
  "label": "form-field"
@@ -47,6 +87,38 @@
47
87
  "value": "input",
48
88
  "label": "input"
49
89
  },
90
+ {
91
+ "value": "input-mask",
92
+ "label": "input-mask"
93
+ },
94
+ {
95
+ "value": "input-otp",
96
+ "label": "input-otp"
97
+ },
98
+ {
99
+ "value": "number-input",
100
+ "label": "number-input"
101
+ },
102
+ {
103
+ "value": "pagination",
104
+ "label": "pagination"
105
+ },
106
+ {
107
+ "value": "password",
108
+ "label": "password"
109
+ },
110
+ {
111
+ "value": "popover",
112
+ "label": "popover"
113
+ },
114
+ {
115
+ "value": "progress",
116
+ "label": "progress"
117
+ },
118
+ {
119
+ "value": "select",
120
+ "label": "select"
121
+ },
50
122
  {
51
123
  "value": "separator",
52
124
  "label": "separator"
@@ -55,13 +127,41 @@
55
127
  "value": "skeleton",
56
128
  "label": "skeleton"
57
129
  },
130
+ {
131
+ "value": "slider",
132
+ "label": "slider"
133
+ },
58
134
  {
59
135
  "value": "switch",
60
136
  "label": "switch"
61
137
  },
138
+ {
139
+ "value": "tabs",
140
+ "label": "tabs"
141
+ },
142
+ {
143
+ "value": "tags-input",
144
+ "label": "tags-input"
145
+ },
62
146
  {
63
147
  "value": "textarea",
64
148
  "label": "textarea"
149
+ },
150
+ {
151
+ "value": "toast",
152
+ "label": "toast"
153
+ },
154
+ {
155
+ "value": "toggle-group",
156
+ "label": "toggle-group"
157
+ },
158
+ {
159
+ "value": "toolbar",
160
+ "label": "toolbar"
161
+ },
162
+ {
163
+ "value": "tooltip",
164
+ "label": "tooltip"
65
165
  }
66
166
  ]
67
167
  }