@devjuliovilla/jv-ui 1.9.0 → 1.11.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 +266 -3
- package/fesm2022/devjuliovilla-jv-ui.mjs +1317 -208
- package/fesm2022/devjuliovilla-jv-ui.mjs.map +1 -1
- package/package.json +4 -1
- package/types/devjuliovilla-jv-ui.d.ts +193 -9
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ import { ApplicationConfig } from '@angular/core';
|
|
|
20
20
|
import { provideJvUi } from '@devjuliovilla/jv-ui';
|
|
21
21
|
|
|
22
22
|
export const appConfig: ApplicationConfig = {
|
|
23
|
-
providers: [provideJvUi({
|
|
23
|
+
providers: [provideJvUi({ messagesLocale: 'en', formatLocale: 'en-US' })],
|
|
24
24
|
};
|
|
25
25
|
```
|
|
26
26
|
|
|
@@ -42,10 +42,13 @@ export class App {}
|
|
|
42
42
|
| Category | Components |
|
|
43
43
|
|---|---|
|
|
44
44
|
| Buttons | `JvButton`, `JvButtonGroup`, `JvIconButton` |
|
|
45
|
-
| Forms | `JvInput`, `JvTextarea`, `JvCode`, `JvSelect`, `JvCheckbox`, `JvRadio`, `JvSwitch`, `JvFormContainer` |
|
|
45
|
+
| Forms | `JvInput`, `JvTextarea`, `JvCode`, `JvSelect`, `JvCheckbox`, `JvRadio`, `JvSwitch`, `JvDatePicker`, `JvModalSelector`, `JvFileInput`, `JvFormContainer` |
|
|
46
46
|
| Data Grid | `JvGrid` — full-featured data table (see below) |
|
|
47
47
|
| Containers | `JvCard`, `JvSection`, `JvDivider` |
|
|
48
48
|
| List | `JvList`, `JvListItem` — list with title, description, icons, badges, and interactive items |
|
|
49
|
+
| Tabs | `JvTabs`, `JvTabPanelDirective` — horizontal tabs with keyboard navigation and animated transitions |
|
|
50
|
+
| Slider | `JvImageSlider` — responsive image slider with thumbnails and keyboard navigation |
|
|
51
|
+
| Gallery | `JvImageGallery` — horizontal image gallery with wheel scrolling and full-screen viewer |
|
|
49
52
|
| Feedback | `JvAlert`, `JvBadge`, `JvLoader`, `JvToast` |
|
|
50
53
|
| Dialogs | `JvDialog`, `JvConfirmDialog` |
|
|
51
54
|
| Layout | `JvDashboardShell`, `JvSidebar`, `JvTopbar`, `JvBreadcrumb`, `JvPage` |
|
|
@@ -124,7 +127,8 @@ import { JvGridComponent } from '@devjuliovilla/jv-ui';
|
|
|
124
127
|
| `editOptions` | `{ label: string; value: unknown }[]` | Options for select editor |
|
|
125
128
|
| `width` | `string` | Column width (e.g. '8rem') |
|
|
126
129
|
| `align` | `'start' \| 'center' \| 'end'` | Text alignment |
|
|
127
|
-
| `type` | `'text' \| 'number' \| 'currency' \| 'date' \| 'datetime' \| 'boolean'` | Data type for formatting |
|
|
130
|
+
| `type` | `'text' \| 'integer' \| 'number' \| 'currency' \| 'percent' \| 'date' \| 'time' \| 'datetime' \| 'boolean'` | Data type for formatting |
|
|
131
|
+
| `formatOptions` | `Intl.NumberFormatOptions & Intl.DateTimeFormatOptions` | Per-column formatting overrides |
|
|
128
132
|
| `format` | `(value, row) => string` | Custom display formatter |
|
|
129
133
|
| `children` | `JvGridColumn<T>[]` | Child columns for grouped headers |
|
|
130
134
|
| `resizable` | `boolean` | Allow column resize |
|
|
@@ -292,6 +296,265 @@ import { JvPaginationComponent } from '@devjuliovilla/jv-ui';
|
|
|
292
296
|
|---|---|
|
|
293
297
|
| `pageChange` | `{ pageIndex: number; pageSize: number }` |
|
|
294
298
|
|
|
299
|
+
## Tabs API
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
import { JvTabsComponent, JvTabPanelDirective, JvTabItem } from '@devjuliovilla/jv-ui';
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Inputs:**
|
|
306
|
+
|
|
307
|
+
| Input | Type | Default | Description |
|
|
308
|
+
|---|---|---|---|
|
|
309
|
+
| `tabs` | `JvTabItem[]` | `[]` | Tab definitions (`{ id, label, icon?, disabled? }`) |
|
|
310
|
+
| `activeTabId` | `string \| null` | `null` | Controlled active tab ID |
|
|
311
|
+
| `keepMounted` | `boolean` | `true` | Keep all panels in DOM; `false` renders only active panel |
|
|
312
|
+
| `transition` | `'none' \| 'fade' \| 'slide' \| null` | `null` | Panel transition animation (falls back to global config) |
|
|
313
|
+
|
|
314
|
+
**Outputs:**
|
|
315
|
+
|
|
316
|
+
| Output | Type |
|
|
317
|
+
|---|---|
|
|
318
|
+
| `activeTabChange` | `string` |
|
|
319
|
+
|
|
320
|
+
**Content projection:** use `jvTabPanel` directive on `ng-template` to define panel content:
|
|
321
|
+
|
|
322
|
+
```html
|
|
323
|
+
<jv-tabs [tabs]="tabs" [activeTabId]="activeTabId()" (activeTabChange)="activeTabId.set($event)">
|
|
324
|
+
<ng-template jvTabPanel="overview">
|
|
325
|
+
<p>Overview content</p>
|
|
326
|
+
</ng-template>
|
|
327
|
+
<ng-template jvTabPanel="analytics">
|
|
328
|
+
<p>Analytics content</p>
|
|
329
|
+
</ng-template>
|
|
330
|
+
</jv-tabs>
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Tab Transitions
|
|
334
|
+
|
|
335
|
+
Tabs support animated transitions between panels. Configure globally via `provideJvUi()` or per-instance via the `transition` input:
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// Global default
|
|
339
|
+
provideJvUi({ tabsTransition: 'fade' })
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
// Per-instance override
|
|
344
|
+
<jv-tabs transition="slide" [keepMounted]="false">...</jv-tabs>
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
| Transition | `keepMounted=true` | `keepMounted=false` | Description |
|
|
348
|
+
|---|---|---|---|
|
|
349
|
+
| `'none'` | Instant switch | Instant switch | No animation |
|
|
350
|
+
| `'fade'` | Opacity cross-fade | Opacity cross-fade | Smooth fade between panels |
|
|
351
|
+
| `'slide'` | Falls back to `'fade'` | Directional slide | Slides left/right based on tab index |
|
|
352
|
+
|
|
353
|
+
**Note:** `slide` requires `keepMounted=false` because it needs to animate both entering and exiting panels simultaneously. When used with `keepMounted=true`, it automatically falls back to `fade`.
|
|
354
|
+
|
|
355
|
+
### Tabs Example
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
import { Component, signal } from '@angular/core';
|
|
359
|
+
import { JvTabItem, JvTabPanelDirective, JvTabsComponent } from '@devjuliovilla/jv-ui';
|
|
360
|
+
|
|
361
|
+
@Component({
|
|
362
|
+
standalone: true,
|
|
363
|
+
imports: [JvTabsComponent, JvTabPanelDirective],
|
|
364
|
+
template: `
|
|
365
|
+
<jv-tabs
|
|
366
|
+
[tabs]="tabs"
|
|
367
|
+
[activeTabId]="activeTabId()"
|
|
368
|
+
transition="fade"
|
|
369
|
+
(activeTabChange)="activeTabId.set($event)"
|
|
370
|
+
>
|
|
371
|
+
<ng-template jvTabPanel="overview">
|
|
372
|
+
<p>Overview content</p>
|
|
373
|
+
</ng-template>
|
|
374
|
+
<ng-template jvTabPanel="analytics">
|
|
375
|
+
<p>Analytics content</p>
|
|
376
|
+
</ng-template>
|
|
377
|
+
</jv-tabs>
|
|
378
|
+
`,
|
|
379
|
+
})
|
|
380
|
+
export class TabsExampleComponent {
|
|
381
|
+
readonly activeTabId = signal('overview');
|
|
382
|
+
readonly tabs: JvTabItem[] = [
|
|
383
|
+
{ id: 'overview', label: 'Overview' },
|
|
384
|
+
{ id: 'analytics', label: 'Analytics', icon: 'chart-column' },
|
|
385
|
+
];
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Image Slider API
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
import { JvImageSliderComponent, JvSliderImage } from '@devjuliovilla/jv-ui';
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**JvSliderImage:**
|
|
396
|
+
|
|
397
|
+
| Property | Type | Required | Description |
|
|
398
|
+
|---|---|---|---|
|
|
399
|
+
| `src` | `string` | Yes | Image URL |
|
|
400
|
+
| `alt` | `string` | Yes | Alternative text for accessibility |
|
|
401
|
+
| `description` | `string` | No | Caption displayed below the image |
|
|
402
|
+
| `thumbnail` | `string` | No | Custom thumbnail URL (defaults to `src`) |
|
|
403
|
+
|
|
404
|
+
**Inputs:**
|
|
405
|
+
|
|
406
|
+
| Input | Type | Default | Description |
|
|
407
|
+
|---|---|---|---|
|
|
408
|
+
| `images` | `JvSliderImage[]` | `[]` | Array of images to display |
|
|
409
|
+
| `showThumbnails` | `boolean` | `true` | Show thumbnail strip below slider |
|
|
410
|
+
| `showDescription` | `boolean` | `true` | Show image description |
|
|
411
|
+
|
|
412
|
+
**Outputs:**
|
|
413
|
+
|
|
414
|
+
| Output | Type | Description |
|
|
415
|
+
|---|---|---|
|
|
416
|
+
| `imageChange` | `number` | Emits index when active image changes |
|
|
417
|
+
|
|
418
|
+
**i18n support:**
|
|
419
|
+
|
|
420
|
+
The component automatically translates aria labels using `JvTranslationService`:
|
|
421
|
+
|
|
422
|
+
| Key | English | Spanish |
|
|
423
|
+
|---|---|---|
|
|
424
|
+
| `slider.prevImage` | Previous image | Imagen anterior |
|
|
425
|
+
| `slider.nextImage` | Next image | Imagen siguiente |
|
|
426
|
+
| `slider.thumbnailList` | Image thumbnails | Miniaturas de imagenes |
|
|
427
|
+
|
|
428
|
+
### Features
|
|
429
|
+
|
|
430
|
+
- **Keyboard navigation:** ArrowLeft/ArrowRight to navigate, Home/End for first/last image
|
|
431
|
+
- **Responsive:** Images scale to fit container with `object-fit: contain`
|
|
432
|
+
- **Thumbnails:** Scrollable thumbnail strip with active state indicator
|
|
433
|
+
- **Single image mode:** Navigation controls hidden when only one image is provided
|
|
434
|
+
- **Lazy loading:** Images use native `loading="lazy"` attribute
|
|
435
|
+
- **i18n:** Aria labels automatically translated based on configured locale
|
|
436
|
+
|
|
437
|
+
### Example
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
import { Component } from '@angular/core';
|
|
441
|
+
import { JvImageSliderComponent, JvSliderImage } from '@devjuliovilla/jv-ui';
|
|
442
|
+
|
|
443
|
+
@Component({
|
|
444
|
+
standalone: true,
|
|
445
|
+
imports: [JvImageSliderComponent],
|
|
446
|
+
template: `
|
|
447
|
+
<jv-image-slider
|
|
448
|
+
[images]="images"
|
|
449
|
+
[showThumbnails]="true"
|
|
450
|
+
[showDescription]="true"
|
|
451
|
+
(imageChange)="onImageChange($event)"
|
|
452
|
+
/>
|
|
453
|
+
`,
|
|
454
|
+
})
|
|
455
|
+
export class SliderComponent {
|
|
456
|
+
readonly images: JvSliderImage[] = [
|
|
457
|
+
{ src: 'photo1.jpg', alt: 'Sunset', description: 'Beautiful sunset over the ocean' },
|
|
458
|
+
{ src: 'photo2.jpg', alt: 'Mountain', description: 'Snow-capped mountain peak' },
|
|
459
|
+
{ src: 'photo3.jpg', alt: 'Forest', description: 'Dense forest trail' },
|
|
460
|
+
];
|
|
461
|
+
|
|
462
|
+
onImageChange(index: number) {
|
|
463
|
+
console.log('Viewing image:', index);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
## Image Gallery API
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
import { JvImageGalleryComponent, JvGalleryImage, JvGalleryAction } from '@devjuliovilla/jv-ui';
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
**JvGalleryImage:**
|
|
475
|
+
|
|
476
|
+
| Property | Type | Required | Description |
|
|
477
|
+
|---|---|---|---|
|
|
478
|
+
| `src` | `string` | Yes | Image URL |
|
|
479
|
+
| `alt` | `string` | Yes | Alternative text for accessibility |
|
|
480
|
+
| `thumbnail` | `string` | No | Custom thumbnail URL (defaults to `src`) |
|
|
481
|
+
|
|
482
|
+
**JvGalleryAction:**
|
|
483
|
+
|
|
484
|
+
| Property | Type | Required | Description |
|
|
485
|
+
|---|---|---|---|
|
|
486
|
+
| `id` | `string` | Yes | Unique action identifier |
|
|
487
|
+
| `label` | `string` | Yes | Button label text |
|
|
488
|
+
| `icon` | `string` | No | Lucide icon name |
|
|
489
|
+
| `tone` | `JvIntent` | No | Button variant |
|
|
490
|
+
|
|
491
|
+
**Inputs:**
|
|
492
|
+
|
|
493
|
+
| Input | Type | Default | Description |
|
|
494
|
+
|---|---|---|---|
|
|
495
|
+
| `images` | `JvGalleryImage[]` | `[]` | Array of images to display |
|
|
496
|
+
| `stripHeightVh` | `number` | `25` | Height of the thumbnail strip in viewport-height units, clamped between `0` and `100` |
|
|
497
|
+
| `actions` | `JvGalleryAction[]` | `[]` | Action buttons shown in dialog footer |
|
|
498
|
+
|
|
499
|
+
**Outputs:**
|
|
500
|
+
|
|
501
|
+
| Output | Type | Description |
|
|
502
|
+
|---|---|---|
|
|
503
|
+
| `imageClick` | `JvGalleryImage` | Emits when an image is clicked |
|
|
504
|
+
| `actionClick` | `{ actionId: string; image: JvGalleryImage }` | Emits when an action button is clicked |
|
|
505
|
+
|
|
506
|
+
### Features
|
|
507
|
+
|
|
508
|
+
- **Horizontal strip:** Scrollable thumbnail strip with configurable height in `vh`
|
|
509
|
+
- **Full-screen viewer:** Click any image to open in a dialog with dark background
|
|
510
|
+
- **Navigation:** Prev/next buttons and keyboard arrows (← →) in the viewer
|
|
511
|
+
- **Configurable actions:** Action buttons in dialog footer (favorite, edit, delete, etc.)
|
|
512
|
+
- **Responsive:** Shows multiple columns on desktop, single column with scroll on mobile
|
|
513
|
+
- **Lazy loading:** All images use native `loading="lazy"` attribute
|
|
514
|
+
- **i18n:** Close and navigation labels automatically translated
|
|
515
|
+
|
|
516
|
+
### Example
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
import { Component } from '@angular/core';
|
|
520
|
+
import { JvImageGalleryComponent, JvGalleryImage, JvGalleryAction } from '@devjuliovilla/jv-ui';
|
|
521
|
+
|
|
522
|
+
@Component({
|
|
523
|
+
standalone: true,
|
|
524
|
+
imports: [JvImageGalleryComponent],
|
|
525
|
+
template: `
|
|
526
|
+
<jv-image-gallery
|
|
527
|
+
[images]="images"
|
|
528
|
+
[stripHeightVh]="30"
|
|
529
|
+
[actions]="actions"
|
|
530
|
+
(imageClick)="onImageClick($event)"
|
|
531
|
+
(actionClick)="onActionClick($event)"
|
|
532
|
+
/>
|
|
533
|
+
`,
|
|
534
|
+
})
|
|
535
|
+
export class GalleryComponent {
|
|
536
|
+
readonly images: JvGalleryImage[] = [
|
|
537
|
+
{ src: 'photo1.jpg', alt: 'Sunset' },
|
|
538
|
+
{ src: 'photo2.jpg', alt: 'Mountain' },
|
|
539
|
+
{ src: 'photo3.jpg', alt: 'Forest' },
|
|
540
|
+
];
|
|
541
|
+
|
|
542
|
+
readonly actions: JvGalleryAction[] = [
|
|
543
|
+
{ id: 'favorite', label: 'Favorite', icon: 'heart', tone: 'danger' },
|
|
544
|
+
{ id: 'edit', label: 'Edit', icon: 'pencil' },
|
|
545
|
+
{ id: 'delete', label: 'Delete', icon: 'trash-2', tone: 'danger' },
|
|
546
|
+
];
|
|
547
|
+
|
|
548
|
+
onImageClick(image: JvGalleryImage) {
|
|
549
|
+
console.log('Viewing:', image.alt);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
onActionClick(event: { actionId: string; image: JvGalleryImage }) {
|
|
553
|
+
console.log(event.actionId, 'on', event.image.alt);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
295
558
|
## Textarea API
|
|
296
559
|
|
|
297
560
|
```typescript
|