@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.
- package/README.md +28 -1
- package/dist/init/css.js +17 -0
- package/dist/init/index.js +7 -5
- package/dist/init/items.js +9 -0
- package/dist/registry.json +482 -1
- package/dist/templates/components/avatar/avatar.ts +1 -1
- package/dist/templates/components/avatar/avatar.variants.ts +4 -4
- package/dist/templates/components/badge/badge.ts +41 -6
- package/dist/templates/components/badge/badge.variants.ts +105 -11
- package/dist/templates/components/button/button.ts +74 -7
- package/dist/templates/components/button/button.variants.ts +145 -21
- package/dist/templates/components/calendar/calendar-texts.ts +72 -0
- package/dist/templates/components/calendar/calendar.ts +588 -0
- package/dist/templates/components/calendar/dates.ts +181 -0
- package/dist/templates/components/calendar/index.ts +3 -0
- package/dist/templates/components/card/card.ts +8 -5
- package/dist/templates/components/checkbox/checkbox.ts +3 -3
- package/dist/templates/components/chip/chip-texts.ts +40 -0
- package/dist/templates/components/chip/chip.ts +116 -0
- package/dist/templates/components/chip/index.ts +2 -0
- package/dist/templates/components/color-picker/color-picker-texts.ts +57 -0
- package/dist/templates/components/color-picker/color-picker.ts +718 -0
- package/dist/templates/components/color-picker/color.ts +157 -0
- package/dist/templates/components/color-picker/index.ts +3 -0
- package/dist/templates/components/combobox/combobox-texts.ts +70 -0
- package/dist/templates/components/combobox/combobox.ts +798 -0
- package/dist/templates/components/combobox/index.ts +2 -0
- package/dist/templates/components/confirm/confirm-texts.ts +46 -0
- package/dist/templates/components/confirm/confirm.ts +190 -0
- package/dist/templates/components/confirm/index.ts +2 -0
- package/dist/templates/components/context-menu/context-menu.ts +378 -0
- package/dist/templates/components/context-menu/index.ts +14 -0
- package/dist/templates/components/date-picker/date-picker.ts +240 -0
- package/dist/templates/components/date-picker/index.ts +3 -0
- package/dist/templates/components/date-range/date-range.ts +308 -0
- package/dist/templates/components/date-range/index.ts +1 -0
- package/dist/templates/components/dialog/dialog-texts.ts +41 -0
- package/dist/templates/components/dialog/dialog.ts +701 -0
- package/dist/templates/components/dialog/index.ts +18 -0
- package/dist/templates/components/dropdown-menu/dropdown-menu.ts +252 -0
- package/dist/templates/components/dropdown-menu/index.ts +14 -0
- package/dist/templates/components/file-upload/file-upload-texts.ts +77 -0
- package/dist/templates/components/file-upload/file-upload.ts +698 -0
- package/dist/templates/components/file-upload/index.ts +2 -0
- package/dist/templates/components/form-field/form-error.ts +1 -1
- package/dist/templates/components/form-field/form-field.ts +3 -2
- package/dist/templates/components/input/input.variants.ts +6 -4
- package/dist/templates/components/input-mask/index.ts +1 -0
- package/dist/templates/components/input-mask/input-mask.ts +319 -0
- package/dist/templates/components/input-otp/index.ts +1 -0
- package/dist/templates/components/input-otp/input-otp.ts +212 -0
- package/dist/templates/components/menu/index.ts +15 -0
- package/dist/templates/components/menu/menu.ts +656 -0
- package/dist/templates/components/number-input/index.ts +2 -0
- package/dist/templates/components/number-input/number-input-texts.ts +46 -0
- package/dist/templates/components/number-input/number-input.ts +450 -0
- package/dist/templates/components/option-list/index.ts +11 -0
- package/dist/templates/components/option-list/option-list.ts +518 -0
- package/dist/templates/components/pagination/index.ts +2 -0
- package/dist/templates/components/pagination/pagination-page-size.ts +74 -0
- package/dist/templates/components/pagination/pagination-texts.ts +69 -0
- package/dist/templates/components/pagination/pagination.ts +443 -0
- package/dist/templates/components/password/index.ts +2 -0
- package/dist/templates/components/password/password-texts.ts +68 -0
- package/dist/templates/components/password/password.ts +363 -0
- package/dist/templates/components/popover/index.ts +12 -0
- package/dist/templates/components/popover/popover.ts +407 -0
- package/dist/templates/components/progress/index.ts +1 -0
- package/dist/templates/components/progress/progress.ts +217 -0
- package/dist/templates/components/select/index.ts +12 -0
- package/dist/templates/components/select/select-texts.ts +62 -0
- package/dist/templates/components/select/select.ts +1086 -0
- package/dist/templates/components/separator/separator.variants.ts +10 -7
- package/dist/templates/components/skeleton/skeleton.ts +4 -1
- package/dist/templates/components/slider/index.ts +2 -0
- package/dist/templates/components/slider/slider-texts.ts +26 -0
- package/dist/templates/components/slider/slider.ts +425 -0
- package/dist/templates/components/switch/switch.ts +6 -6
- package/dist/templates/components/tabs/index.ts +2 -0
- package/dist/templates/components/tabs/tabs.ts +426 -0
- package/dist/templates/components/tags-input/index.ts +2 -0
- package/dist/templates/components/tags-input/tags-input-texts.ts +44 -0
- package/dist/templates/components/tags-input/tags-input.ts +303 -0
- package/dist/templates/components/textarea/textarea.variants.ts +14 -11
- package/dist/templates/components/toast/index.ts +3 -0
- package/dist/templates/components/toast/toast-config.ts +45 -0
- package/dist/templates/components/toast/toast-texts.ts +46 -0
- package/dist/templates/components/toast/toast.ts +1000 -0
- package/dist/templates/components/toggle-group/index.ts +1 -0
- package/dist/templates/components/toggle-group/toggle-group.ts +406 -0
- package/dist/templates/components/toolbar/index.ts +1 -0
- package/dist/templates/components/toolbar/toolbar.ts +377 -0
- package/dist/templates/components/tooltip/index.ts +7 -0
- package/dist/templates/components/tooltip/tooltip.ts +407 -0
- package/dist/templates/theme/provider.ts +75 -6
- package/dist/templates/theme/theme-base.css +410 -9
- package/dist/templates/theme/types.ts +494 -4
- package/dist/templates/utils/cn.ts +15 -1
- package/dist/templates/utils/control-styles.ts +2 -2
- package/dist/templates/utils/overlay.ts +153 -0
- package/dist/ui/index.js +184 -8
- package/dist/ui/schema.json +100 -0
- package/dist/utils/write-files.js +166 -59
- 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).
|
|
21
|
-
*
|
|
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
|
-
|
|
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] =
|
|
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
|
-
|
|
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
|
|
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)) ??
|
|
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
|
-
|
|
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.');
|
package/dist/ui/schema.json
CHANGED
|
@@ -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
|
}
|