@mimi-ng/cli 0.3.0 → 0.5.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 (50) hide show
  1. package/README.md +42 -1
  2. package/dist/init/css.js +1 -1
  3. package/dist/init/index.js +33 -0
  4. package/dist/init/paths.js +20 -0
  5. package/dist/registry.js +4 -1
  6. package/dist/registry.json +198 -1
  7. package/dist/templates/blocks/login-01/index.ts +1 -0
  8. package/dist/templates/blocks/login-01/login-01.html +174 -0
  9. package/dist/templates/blocks/login-01/login-01.ts +114 -0
  10. package/dist/templates/blocks/login-02/index.ts +1 -0
  11. package/dist/templates/blocks/login-02/login-02.html +186 -0
  12. package/dist/templates/blocks/login-02/login-02.ts +101 -0
  13. package/dist/templates/blocks/otp-01/index.ts +1 -0
  14. package/dist/templates/blocks/otp-01/otp-01.html +166 -0
  15. package/dist/templates/blocks/otp-01/otp-01.ts +221 -0
  16. package/dist/templates/blocks/pricing-01/index.ts +1 -0
  17. package/dist/templates/blocks/pricing-01/pricing-01.html +173 -0
  18. package/dist/templates/blocks/pricing-01/pricing-01.ts +178 -0
  19. package/dist/templates/blocks/settings-01/index.ts +1 -0
  20. package/dist/templates/blocks/settings-01/settings-01.html +424 -0
  21. package/dist/templates/blocks/settings-01/settings-01.ts +392 -0
  22. package/dist/templates/blocks/signup-01/index.ts +1 -0
  23. package/dist/templates/blocks/signup-01/signup-01.html +332 -0
  24. package/dist/templates/blocks/signup-01/signup-01.ts +186 -0
  25. package/dist/templates/blocks/table-01/index.ts +1 -0
  26. package/dist/templates/blocks/table-01/table-01.html +214 -0
  27. package/dist/templates/blocks/table-01/table-01.ts +266 -0
  28. package/dist/templates/components/checkbox/checkbox.ts +14 -5
  29. package/dist/templates/components/command/command-texts.ts +65 -0
  30. package/dist/templates/components/command/command.ts +553 -0
  31. package/dist/templates/components/command/index.ts +13 -0
  32. package/dist/templates/components/data-table/data-table-texts.ts +110 -0
  33. package/dist/templates/components/data-table/data-table.ts +1153 -0
  34. package/dist/templates/components/data-table/index.ts +18 -0
  35. package/dist/templates/components/sortable-list/index.ts +9 -0
  36. package/dist/templates/components/sortable-list/sortable-list-texts.ts +71 -0
  37. package/dist/templates/components/sortable-list/sortable-list.ts +510 -0
  38. package/dist/templates/components/tabs/tabs.ts +88 -23
  39. package/dist/templates/components/tree/index.ts +9 -0
  40. package/dist/templates/components/tree/tree-texts.ts +45 -0
  41. package/dist/templates/components/tree/tree.ts +730 -0
  42. package/dist/templates/theme/provider.ts +4 -0
  43. package/dist/templates/theme/types.ts +84 -0
  44. package/dist/ui/index.js +323 -13
  45. package/dist/ui/schema.json +50 -2
  46. package/dist/utils/pages.js +138 -0
  47. package/dist/utils/project.js +59 -0
  48. package/dist/utils/tailwind.js +84 -0
  49. package/dist/utils/write-files.js +63 -8
  50. package/package.json +1 -1
@@ -97,37 +97,75 @@ export class MimiTabsOutlet {
97
97
  });
98
98
  }
99
99
 
100
+ /**
101
+ * Orientación de la fila de pestañas (B.10): horizontal (por defecto) o vertical, para una
102
+ * navegación lateral. En vertical, las flechas son ↑/↓ (las pone aria) y el panel va al lado.
103
+ */
104
+ export type MimiTabsOrientation = 'horizontal' | 'vertical';
105
+
100
106
  /** El contenedor visible de las pestañas (recibe el `class` del usuario). */
101
107
  const containerVariants = cva('relative font-sans', {
102
108
  variants: {
103
109
  variant: {
104
- underline: 'border-b border-border',
110
+ underline: 'border-border',
105
111
  // 4px fijos (no rem): el indicador resta los mismos 8px.
106
- pill: 'max-w-[520px] rounded-[calc(var(--mimi-radius)_+_4px)] bg-[color:var(--mimi-tabs-pill-bg,var(--mimi-muted))] p-[4px]',
112
+ pill: 'rounded-[calc(var(--mimi-radius)_+_4px)] bg-[color:var(--mimi-tabs-pill-bg,var(--mimi-muted))] p-[4px]',
107
113
  },
114
+ orientation: { horizontal: '', vertical: 'self-start' },
108
115
  },
109
- defaultVariants: { variant: 'underline' },
116
+ compoundVariants: [
117
+ { variant: 'underline', orientation: 'horizontal', class: 'border-b' },
118
+ { variant: 'underline', orientation: 'vertical', class: 'border-s' },
119
+ { variant: 'pill', orientation: 'horizontal', class: 'max-w-[520px]' },
120
+ ],
121
+ defaultVariants: { variant: 'underline', orientation: 'horizontal' },
110
122
  });
111
123
 
112
124
  /**
113
- * El indicador: columnas iguales, así que su ancho es el de una columna y se desplaza su propio
114
- * ancho por cada pestaña (sin medir nada). En derecha a izquierda, al revés.
125
+ * El indicador: columnas (o filas) iguales, así que su tamaño es el de una pestaña y se desplaza
126
+ * su propio ancho (o alto) por cada una (sin medir nada). En derecha a izquierda, al revés.
115
127
  */
116
128
  const indicatorVariants = cva(
117
129
  [
118
130
  'pointer-events-none absolute',
119
- 'translate-x-[calc(100%_*_var(--mimi-tabs-index))] rtl:translate-x-[calc(-100%_*_var(--mimi-tabs-index))]',
120
131
  'transition-[translate] duration-[450ms] ease-[var(--mimi-tabs-spring,cubic-bezier(0.3,1.35,0.5,1))] motion-reduce:transition-none',
121
132
  ],
122
133
  {
123
134
  variants: {
124
135
  variant: {
125
- underline:
126
- '-bottom-px start-0 h-0.5 w-[calc(100%_/_var(--mimi-tabs-count))] rounded-[2px] bg-[color:var(--mimi-tabs-indicator,var(--mimi-foreground))]',
127
- pill: 'start-[4px] top-[4px] bottom-[4px] w-[calc((100%_-_8px)_/_var(--mimi-tabs-count))] rounded-[var(--mimi-radius)] bg-[color:var(--mimi-tabs-pill-active,var(--mimi-card))] shadow-neutral',
136
+ underline: 'rounded-[2px] bg-[color:var(--mimi-tabs-indicator,var(--mimi-foreground))]',
137
+ pill: 'rounded-[var(--mimi-radius)] bg-[color:var(--mimi-tabs-pill-active,var(--mimi-card))] shadow-neutral',
138
+ },
139
+ orientation: {
140
+ horizontal:
141
+ 'translate-x-[calc(100%_*_var(--mimi-tabs-index))] rtl:translate-x-[calc(-100%_*_var(--mimi-tabs-index))]',
142
+ vertical: 'translate-y-[calc(100%_*_var(--mimi-tabs-index))]',
128
143
  },
129
144
  },
130
- defaultVariants: { variant: 'underline' },
145
+ compoundVariants: [
146
+ {
147
+ variant: 'underline',
148
+ orientation: 'horizontal',
149
+ class: '-bottom-px start-0 h-0.5 w-[calc(100%_/_var(--mimi-tabs-count))]',
150
+ },
151
+ {
152
+ // La barra va a la izquierda (al inicio), sobre el borde del contenedor.
153
+ variant: 'underline',
154
+ orientation: 'vertical',
155
+ class: '-start-px top-0 w-0.5 h-[calc(100%_/_var(--mimi-tabs-count))]',
156
+ },
157
+ {
158
+ variant: 'pill',
159
+ orientation: 'horizontal',
160
+ class: 'start-[4px] top-[4px] bottom-[4px] w-[calc((100%_-_8px)_/_var(--mimi-tabs-count))]',
161
+ },
162
+ {
163
+ variant: 'pill',
164
+ orientation: 'vertical',
165
+ class: 'start-[4px] end-[4px] top-[4px] h-[calc((100%_-_8px)_/_var(--mimi-tabs-count))]',
166
+ },
167
+ ],
168
+ defaultVariants: { variant: 'underline', orientation: 'horizontal' },
131
169
  },
132
170
  );
133
171
 
@@ -148,8 +186,10 @@ const tabVariants = cva(
148
186
  // 34px sin token (el token de alto es el de la subrayada): plan D6.
149
187
  pill: 'h-[34px] gap-1.5 rounded-[var(--mimi-radius)] text-[13.5px] [&_svg]:size-[15px] [&_svg]:shrink-0',
150
188
  },
189
+ // En vertical, el texto al inicio, como una navegación lateral.
190
+ orientation: { horizontal: '', vertical: 'justify-start px-3 text-start' },
151
191
  },
152
- defaultVariants: { variant: 'underline' },
192
+ defaultVariants: { variant: 'underline', orientation: 'horizontal' },
153
193
  },
154
194
  );
155
195
 
@@ -196,11 +236,12 @@ const COUNT_CLASSES =
196
236
  <div
197
237
  ngTabList
198
238
  data-slot="tablist"
239
+ [orientation]="orientation()"
199
240
  [selectedTab]="painted()"
200
241
  (selectedTabChange)="fromAria($event)"
201
242
  [attr.aria-label]="ariaLabel() || null"
202
243
  [attr.aria-labelledby]="ariaLabelledby() || null"
203
- [class]="tablistClasses"
244
+ [class]="tablistClasses()"
204
245
  (click)="choose($event)"
205
246
  (keydown.enter)="choose($event)"
206
247
  (keydown.space)="choose($event)"
@@ -248,12 +289,19 @@ const COUNT_CLASSES =
248
289
  </div>
249
290
  `,
250
291
  host: {
251
- style: 'display: flex; flex-direction: column; gap: 14px',
292
+ // flex-direction va en su binding (B.10), no aquí.
293
+ style: 'display: flex; gap: 14px',
252
294
  // El class es del contenedor de las pestañas; aria-label y aria-labelledby, del tablist.
253
295
  '[attr.class]': 'null',
254
296
  '[attr.aria-label]': 'null',
255
297
  '[attr.aria-labelledby]': 'null',
256
298
  '[attr.data-variant]': 'variant()',
299
+ '[attr.data-orientation]': 'orientation()',
300
+ // En vertical, las pestañas a un lado y el panel al otro. Bindings sueltos (no [style] con
301
+ // un objeto, que sumaba ɵɵstyleMap al JS inicial: spec 10).
302
+ // Siempre con valor: con null, Angular quita también el flex-direction del style estático.
303
+ '[style.flex-direction]': 'orientation() === "vertical" ? "row" : "column"',
304
+ '[style.align-items]': 'orientation() === "vertical" ? "flex-start" : null',
257
305
  },
258
306
  changeDetection: ChangeDetectionStrategy.OnPush,
259
307
  })
@@ -264,6 +312,8 @@ export class MimiTabs {
264
312
  readonly value = model<string | undefined>(undefined);
265
313
  /** Por defecto, `underline`. */
266
314
  readonly variant = input<MimiTabsVariant>('underline');
315
+ /** Por defecto, `horizontal`. Puede cambiar en vivo (por ejemplo, con el ancho). */
316
+ readonly orientation = input<MimiTabsOrientation>('horizontal');
267
317
  /** Conserva el contenido de los paneles al cambiar de pestaña (por defecto se destruye). */
268
318
  readonly preserveContent = input(false, { transform: booleanAttribute });
269
319
  /** Nombre accesible de la fila de pestañas. */
@@ -298,22 +348,37 @@ export class MimiTabs {
298
348
  this.tabs().findIndex((tab) => tab.value() === this.painted()),
299
349
  );
300
350
 
351
+ private readonly variants = computed(() => ({
352
+ variant: this.variant(),
353
+ orientation: this.orientation(),
354
+ }));
301
355
  protected readonly containerClasses = computed(() =>
302
- cn(containerVariants({ variant: this.variant() }), this.userClass()),
356
+ cn(containerVariants(this.variants()), this.userClass()),
303
357
  );
304
- protected readonly indicatorClasses = computed(() =>
305
- indicatorVariants({ variant: this.variant() }),
306
- );
307
- protected readonly tabClasses = computed(() => tabVariants({ variant: this.variant() }));
358
+ protected readonly indicatorClasses = computed(() => indicatorVariants(this.variants()));
359
+ // Con cn(): la vertical cambia `justify-center` por `justify-start` (sin él, quedaban las dos y
360
+ // ganaba la que va después en el CSS).
361
+ protected readonly tabClasses = computed(() => cn(tabVariants(this.variants())));
308
362
  // Sin outline-none: en Tailwind 4 pone --tw-outline-style en none y anula el anillo de foco.
309
- protected readonly tablistClasses = cn(
310
- 'grid grid-cols-[repeat(var(--mimi-tabs-count),minmax(0,1fr))] rounded-[inherit]',
311
- // Con todas deshabilitadas, el foco queda en la fila (aria).
312
- buttonFocusStyles,
363
+ // Las clases de cada orientación, completas (no variantes encadenadas: selectores largos, G2.1).
364
+ protected readonly tablistClasses = computed(() =>
365
+ cn(
366
+ this.orientation() === 'vertical'
367
+ ? 'grid grid-rows-[repeat(var(--mimi-tabs-count),minmax(0,1fr))]'
368
+ : 'grid grid-cols-[repeat(var(--mimi-tabs-count),minmax(0,1fr))]',
369
+ 'rounded-[inherit]',
370
+ // Con todas deshabilitadas, el foco queda en la fila (aria).
371
+ buttonFocusStyles,
372
+ ),
313
373
  );
314
374
  protected readonly countClasses = COUNT_CLASSES;
315
375
  protected readonly panelClasses = computed(() =>
316
- cn('px-0.5 py-1', buttonFocusStyles, this.panelClass()),
376
+ cn(
377
+ 'px-0.5 py-1',
378
+ this.orientation() === 'vertical' && 'min-w-0 flex-1',
379
+ buttonFocusStyles,
380
+ this.panelClass(),
381
+ ),
317
382
  );
318
383
 
319
384
  /** El último valor que puso Mimi (no viene de fuera). */
@@ -0,0 +1,9 @@
1
+ // Solo la API pública: MimiTreeOutlet es interno (se queda en './tree').
2
+ export {
3
+ MimiTree,
4
+ MimiTreeImports,
5
+ type MimiTreeNode,
6
+ type MimiTreeNodeContext,
7
+ MimiTreeNodeTemplate,
8
+ } from './tree';
9
+ export * from './tree-texts';
@@ -0,0 +1,45 @@
1
+ import { InjectionToken, type Provider } from '@angular/core';
2
+
3
+ /*
4
+ * Textos del Tree, en archivo propio y sin @angular/cdk: así se pueden proveer en `app.config.ts`
5
+ * sin llevar el Tree al chunk inicial.
6
+ */
7
+
8
+ /** Textos que el Tree muestra o anuncia. */
9
+ export interface MimiTreeText {
10
+ /** Fila mientras se cargan los hijos de un nodo (carga diferida). */
11
+ loading: string;
12
+ /** Fila cuando la carga falla; se reintenta al volver a abrir el nodo. */
13
+ loadError: string;
14
+ }
15
+
16
+ /** Textos predeterminados (inglés). */
17
+ export const MIMI_TREE_TEXT_EN: MimiTreeText = {
18
+ loading: 'Loading…',
19
+ loadError: 'Couldn’t load. Close and open it again to retry.',
20
+ };
21
+
22
+ /** Textos en español: `provideMimiTreeText(MIMI_TREE_TEXT_ES)`. */
23
+ export const MIMI_TREE_TEXT_ES: MimiTreeText = {
24
+ loading: 'Cargando…',
25
+ loadError: 'No se pudo cargar. Ciérralo y ábrelo para reintentar.',
26
+ };
27
+
28
+ /** Textos activos. Sin `provideMimiTreeText`, los predeterminados en inglés. */
29
+ export const MIMI_TREE_TEXT = new InjectionToken<MimiTreeText>('MIMI_TREE_TEXT', {
30
+ providedIn: 'root',
31
+ factory: () => MIMI_TREE_TEXT_EN,
32
+ });
33
+
34
+ /**
35
+ * Cambia los textos del Tree. Lo que no definas sigue en inglés:
36
+ *
37
+ * ```ts
38
+ * provideMimiTreeText(MIMI_TREE_TEXT_ES)
39
+ * ```
40
+ *
41
+ * Va en `app.config.ts` o en los `providers` de un componente o ruta.
42
+ */
43
+ export function provideMimiTreeText(text: Partial<MimiTreeText>): Provider {
44
+ return { provide: MIMI_TREE_TEXT, useValue: { ...MIMI_TREE_TEXT_EN, ...text } };
45
+ }