diff --git a/src/app/shared/components/tooltip/tooltip.component.html b/src/app/shared/components/tooltip/tooltip.component.html new file mode 100644 index 0000000..35788c8 --- /dev/null +++ b/src/app/shared/components/tooltip/tooltip.component.html @@ -0,0 +1,11 @@ + diff --git a/src/app/shared/components/tooltip/tooltip.component.scss b/src/app/shared/components/tooltip/tooltip.component.scss new file mode 100644 index 0000000..c195b68 --- /dev/null +++ b/src/app/shared/components/tooltip/tooltip.component.scss @@ -0,0 +1,62 @@ +:host { + display: inline-flex; + align-items: center; + margin-left: 0.25rem; + vertical-align: middle; +} + +.tooltip-trigger { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; + border: 0; + background: transparent; + color: var(--tenant-primary, var(--color-primary, #0d6efd)); + font-size: 1em; + line-height: inherit; + + &:focus-visible { + border-radius: 50%; + outline: 2px solid currentColor; + outline-offset: 2px; + } + + &:hover .tooltip-message, + &:focus-visible .tooltip-message { + visibility: visible; + opacity: 1; + transform: translate(-50%, -0.25rem); + } +} + +.tooltip-message { + position: absolute; + z-index: 1100; + bottom: calc(100% + 0.625rem); + left: 50%; + width: max-content; + max-width: min(16rem, 75vw); + padding: 0.5rem 0.75rem; + border-radius: 0.375rem; + border: 1px solid var(--tenant-primary, var(--color-primary, #0d6efd)); + background: #fff; + color: #212529; + font-family: inherit; + font-size: 0.75rem; + font-weight: 400; + line-height: 1.35; + text-align: center; + text-transform: none; + letter-spacing: normal; + white-space: normal; + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translate(-50%, 0); + transition: + opacity 0.15s ease, + transform 0.15s ease, + visibility 0.15s ease; +} diff --git a/src/app/shared/components/tooltip/tooltip.component.spec.ts b/src/app/shared/components/tooltip/tooltip.component.spec.ts new file mode 100644 index 0000000..1702ac7 --- /dev/null +++ b/src/app/shared/components/tooltip/tooltip.component.spec.ts @@ -0,0 +1,32 @@ +import { TestBed, getTestBed } from '@angular/core/testing'; +import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing'; +import { afterEach, beforeAll, describe, expect, it } from 'vitest'; + +import { TooltipComponent } from './tooltip.component'; + +describe('TooltipComponent', () => { + beforeAll(() => { + try { + getTestBed().initTestEnvironment(BrowserTestingModule, platformBrowserTesting()); + } catch { + // Test environment may already be initialized by another setup entrypoint. + } + }); + + afterEach(() => TestBed.resetTestingModule()); + + it('renders the reusable danger information tooltip', async () => { + await TestBed.configureTestingModule({ imports: [TooltipComponent] }).compileComponents(); + const fixture = TestBed.createComponent(TooltipComponent); + fixture.componentRef.setInput('message', 'Este producto no tiene stock disponible.'); + fixture.detectChanges(); + + const element = fixture.nativeElement as HTMLElement; + const trigger = element.querySelector('.tooltip-trigger'); + const message = element.querySelector('.tooltip-message'); + + expect(trigger?.querySelector('i.fa-solid.fa-circle-info')).not.toBeNull(); + expect(message?.textContent?.trim()).toBe('Este producto no tiene stock disponible.'); + expect(trigger?.getAttribute('aria-describedby')).toBe(message?.id); + }); +}); diff --git a/src/app/shared/components/tooltip/tooltip.component.ts b/src/app/shared/components/tooltip/tooltip.component.ts new file mode 100644 index 0000000..9f70c23 --- /dev/null +++ b/src/app/shared/components/tooltip/tooltip.component.ts @@ -0,0 +1,14 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; + +let nextTooltipId = 0; + +@Component({ + selector: 'app-tooltip', + templateUrl: './tooltip.component.html', + styleUrl: './tooltip.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TooltipComponent { + readonly message = input.required(); + protected readonly tooltipId = `app-tooltip-${nextTooltipId++}`; +}