From 93e921fd72e8ba1500efce2f51a7779e1b040fba Mon Sep 17 00:00:00 2001 From: elite-benni Date: Tue, 12 Dec 2023 06:34:28 +0100 Subject: [PATCH 1/4] feat(tabs): improved API by integrating brn to hlm --- .../(tabs)/tabs--vertical.preview.ts | 14 +- .../components/(tabs)/tabs.preview.ts | 204 +++++++++--------- .../src/integration/tabs/tabs--brnonly.cy.ts | 79 +++++++ .../src/lib/brn-tabs-content.directive.ts | 4 + .../src/lib/brn-tabs-trigger.directive.ts | 4 + .../src/lib/hlm-tabs-content.directive.ts | 11 +- .../helm/src/lib/hlm-tabs-list.directive.ts | 2 +- .../src/lib/hlm-tabs-trigger.directive.ts | 10 +- libs/ui/tabs/tabs.stories.ts | 47 ++-- 9 files changed, 254 insertions(+), 121 deletions(-) create mode 100644 apps/ui-storybook-e2e/src/integration/tabs/tabs--brnonly.cy.ts diff --git a/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts b/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts index b7a39cba4..0380cf919 100644 --- a/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts +++ b/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts @@ -49,12 +49,12 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective }, template: ` - - - - + + + + -
+

Account

@@ -75,7 +75,7 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective
-
+

Password

@@ -96,7 +96,7 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective
-
+

Delete Account

diff --git a/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts b/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts index dc21cab99..43f2c26bb 100644 --- a/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts +++ b/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts @@ -49,11 +49,11 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective }, template: ` - - - + + + -
+

Account

@@ -74,7 +74,7 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective
-
+

Password

@@ -102,122 +102,128 @@ export class TabsPreviewComponent {} export const defaultCode = ` import { Component } from '@angular/core'; +import { HlmBadgeDirective } from '@spartan-ng/ui-badge-helm'; +import { HlmButtonDirective } from '@spartan-ng/ui-button-helm'; import { - BrnTabsComponent, - BrnTabsContentDirective, - BrnTabsListComponent, - BrnTabsTriggerDirective -} from '@spartan-ng/ui-tabs-brain'; -import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective } from '@spartan-ng/ui-tabs-helm'; -import { - HlmCardContentDirective, - HlmCardDescriptionDirective, - HlmCardDirective, - HlmCardFooterDirective, HlmCardHeaderDirective, HlmCardTitleDirective + HlmCardContentDirective, + HlmCardDescriptionDirective, + HlmCardDirective, + HlmCardFooterDirective, + HlmCardHeaderDirective, + HlmCardTitleDirective, } from '@spartan-ng/ui-card-helm'; -import { HlmLabelDirective } from '@spartan-ng/ui-label-helm'; import { HlmInputDirective } from '@spartan-ng/ui-input-helm'; -import { HlmButtonDirective } from '@spartan-ng/ui-button-helm'; -import { HlmBadgeDirective } from '@spartan-ng/ui-badge-helm'; +import { HlmLabelDirective } from '@spartan-ng/ui-label-helm'; +import { + BrnTabsComponent, + BrnTabsContentDirective, + BrnTabsListComponent, + BrnTabsTriggerDirective, +} from '@spartan-ng/ui-tabs-brain'; +import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective } from '@spartan-ng/ui-tabs-helm'; @Component({ - selector: 'spartan-tabs-preview', - standalone: true, - imports: [ - BrnTabsComponent, - BrnTabsListComponent, - BrnTabsTriggerDirective, - BrnTabsContentDirective, + selector: 'spartan-tabs-preview', + standalone: true, + imports: [ + BrnTabsComponent, + BrnTabsListComponent, + BrnTabsTriggerDirective, + BrnTabsContentDirective, - HlmTabsListDirective, - HlmTabsTriggerDirective, - HlmTabsContentDirective, + HlmTabsListDirective, + HlmTabsTriggerDirective, + HlmTabsContentDirective, - HlmCardContentDirective, - HlmCardDescriptionDirective, - HlmCardDirective, - HlmCardFooterDirective, - HlmCardHeaderDirective, - HlmCardTitleDirective, + HlmCardContentDirective, + HlmCardDescriptionDirective, + HlmCardDirective, + HlmCardFooterDirective, + HlmCardHeaderDirective, + HlmCardTitleDirective, - HlmLabelDirective, - HlmInputDirective, - HlmButtonDirective, - HlmBadgeDirective, - ], - template: \` - - - - - -
-
-
-

Account

-

- Make changes to your account here. Click save when you're done. -

-
-

- - -

-
- -
-
-
-
-
-
-

Password

-

- Change your password here. After saving, you'll be logged out. -

-
-

- - -

-
- -
-
-
-
- \`, + HlmLabelDirective, + HlmInputDirective, + HlmButtonDirective, + HlmBadgeDirective, + ], + host: { + class: 'block w-full max-w-lg', + }, + template: \` + + + + + +
+
+
+

Account

+

Make changes to your account here. Click save when you're done.

+
+

+ + +

+
+ +
+
+
+
+
+
+

Password

+

Change your password here. After saving, you'll be logged out.

+
+

+ + +

+
+ +
+
+
+
+ \`, }) export class TabsPreviewComponent {} + `; export const defaultImports = ` import { - BrnTabsComponent, - BrnTabsContentDirective, - BrnTabsListComponent, - BrnTabsTriggerDirective + BrnTabsComponent, + BrnTabsContentDirective, + BrnTabsListComponent, + BrnTabsTriggerDirective, } from '@spartan-ng/ui-tabs-brain'; import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective } from '@spartan-ng/ui-tabs-helm'; `; export const defaultSkeleton = ` - - - + + + -
+
Make your account here
-
+
Change your password here
diff --git a/apps/ui-storybook-e2e/src/integration/tabs/tabs--brnonly.cy.ts b/apps/ui-storybook-e2e/src/integration/tabs/tabs--brnonly.cy.ts new file mode 100644 index 000000000..44fc1c868 --- /dev/null +++ b/apps/ui-storybook-e2e/src/integration/tabs/tabs--brnonly.cy.ts @@ -0,0 +1,79 @@ +describe('tabs--brnonly', () => { + const verifyTabsSetup = () => { + cy.findByRole('tablist').should('exist'); + cy.findByRole('tablist').should('have.attr', 'aria-label'); + cy.findByRole('tablist').should('have.attr', 'data-orientation', 'horizontal'); + cy.findByRole('tablist').should('have.attr', 'aria-orientation', 'horizontal'); + cy.findAllByRole('tab').should('have.length', 2); + cy.findByRole('tab', { name: /account/i }).should('have.attr', 'aria-controls', 'brn-tabs-content-account'); + cy.findByRole('tab', { name: /password/i }).should('have.attr', 'aria-controls', 'brn-tabs-content-password'); + cy.findByRole('tabpanel').should('exist'); + }; + + describe('default', () => { + beforeEach(() => { + cy.visit('/iframe.html?id=tabs--brn-only'); + cy.injectAxe(); + }); + + it('click interactions should render with first tab selected and change to second tab when second tab is clicked', () => { + verifyTabsSetup(); + + cy.findByRole('tab', { name: /password/i }).click(); + + cy.findByRole('tabpanel').should('have.attr', 'aria-labelledby', 'brn-tabs-label-password'); + cy.findByRole('tabpanel').should('have.attr', 'tabindex', '0'); + cy.findByRole('tab', { name: /password/i }).should('have.attr', 'aria-selected', 'true'); + cy.findByRole('tab', { name: /account/i }).should('have.attr', 'aria-selected', 'false'); + cy.get('#brn-tabs-content-password').should('exist'); + + cy.findByRole('tab', { name: /account/i }).click(); + + cy.findByRole('tabpanel').should('have.attr', 'aria-labelledby', 'brn-tabs-label-account'); + cy.findByRole('tabpanel').should('have.attr', 'tabindex', '0'); + cy.findByRole('tab', { name: /account/i }).should('have.attr', 'aria-selected', 'true'); + cy.findByRole('tab', { name: /password/i }).should('have.attr', 'aria-selected', 'false'); + cy.get('#brn-tabs-content-account').should('exist'); + }); + + it('tab and arrow interactions should render with first tab selected and change to second tab when second tab is focused with arrow right, return to first tab with arrow left and do nothing on arrow up or down', () => { + verifyTabsSetup(); + + cy.realPress('Tab'); + cy.realPress('ArrowRight'); + cy.findByRole('tabpanel').should('have.attr', 'aria-labelledby', 'brn-tabs-label-password'); + cy.findByRole('tabpanel').should('have.attr', 'tabindex', '0'); + cy.get('#brn-tabs-content-password').should('exist'); + + cy.realPress('ArrowLeft'); + cy.findByRole('tabpanel').should('have.attr', 'aria-labelledby', 'brn-tabs-label-account'); + cy.findByRole('tabpanel').should('have.attr', 'tabindex', '0'); + cy.get('#brn-tabs-content-account').should('exist'); + + // should ignore up and down + cy.realPress('ArrowUp'); + cy.get('#brn-tabs-content-account').should('exist'); + + cy.realPress('ArrowDown'); + cy.get('#brn-tabs-content-account').should('exist'); + + // should jump to last on end + cy.realPress('End'); + cy.findByRole('tabpanel').should('have.attr', 'aria-labelledby', 'brn-tabs-label-password'); + cy.findByRole('tabpanel').should('have.attr', 'tabindex', '0'); + cy.get('#brn-tabs-content-password').should('exist'); + + // should wrap arround + cy.realPress('ArrowRight'); + cy.findByRole('tabpanel').should('have.attr', 'aria-labelledby', 'brn-tabs-label-account'); + cy.findByRole('tabpanel').should('have.attr', 'tabindex', '0'); + cy.get('#brn-tabs-content-account').should('exist'); + + // jump between list and panel on tab + cy.realPress('Tab'); + cy.findByRole('tabpanel').should('be.focused'); + cy.realPress(['Shift', 'Tab']); + cy.findByRole('tab', { name: /account/i }).should('be.focused'); + }); + }); +}); diff --git a/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts b/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts index a73c69897..263ef8248 100644 --- a/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts +++ b/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts @@ -29,6 +29,10 @@ export class BrnTabsContentDirective { this._root.registerContent(key, this); } + public setContentFor(key: string) { + this.contentFor = key; + } + public focus() { this._elementRef.nativeElement.focus(); } diff --git a/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts b/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts index cc4d423e2..fa7a11864 100644 --- a/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts +++ b/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts @@ -37,6 +37,10 @@ export class BrnTabsTriggerDirective { @Input() public disabled = false; + public setTriggerFor(key: string) { + this.triggerFor = key; + } + public focus() { this._elementRef.nativeElement.focus(); if (this._root.$activationMode() === 'automatic') { diff --git a/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts b/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts index a832c9a3d..d57304bfe 100644 --- a/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts +++ b/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts @@ -1,21 +1,30 @@ -import { Directive, Input, computed, signal } from '@angular/core'; +import { Directive, Input, computed, inject, signal } from '@angular/core'; import { hlm } from '@spartan-ng/ui-core'; +import { BrnTabsContentDirective } from '@spartan-ng/ui-tabs-brain'; import { ClassValue } from 'clsx'; @Directive({ selector: '[hlmTabsContent]', standalone: true, + hostDirectives: [BrnTabsContentDirective], host: { '[class]': '_computedClass()', }, }) export class HlmTabsContentDirective { + private readonly _brn = inject(BrnTabsContentDirective); private readonly _userCls = signal(''); @Input() set class(userCls: ClassValue) { this._userCls.set(userCls); } + @Input('hlmTabsContent') + set contentFor(key: string) { + console.log('contentFor', key); + this._brn?.setContentFor(key); + } + protected _computedClass = computed(() => this._generateClass()); private _generateClass() { return hlm( diff --git a/libs/ui/tabs/helm/src/lib/hlm-tabs-list.directive.ts b/libs/ui/tabs/helm/src/lib/hlm-tabs-list.directive.ts index 01a5df7ab..6c6831cd6 100644 --- a/libs/ui/tabs/helm/src/lib/hlm-tabs-list.directive.ts +++ b/libs/ui/tabs/helm/src/lib/hlm-tabs-list.directive.ts @@ -20,7 +20,7 @@ export const listVariants = cva( type ListVariants = VariantProps; @Directive({ - selector: '[hlmTabsList]', + selector: '[hlmTabsList], brn-tabs-list[hlm]', standalone: true, host: { '[class]': '_computedClass()', diff --git a/libs/ui/tabs/helm/src/lib/hlm-tabs-trigger.directive.ts b/libs/ui/tabs/helm/src/lib/hlm-tabs-trigger.directive.ts index 51c814314..89bc60fa3 100644 --- a/libs/ui/tabs/helm/src/lib/hlm-tabs-trigger.directive.ts +++ b/libs/ui/tabs/helm/src/lib/hlm-tabs-trigger.directive.ts @@ -1,5 +1,6 @@ -import { Directive, Input, computed, signal } from '@angular/core'; +import { Directive, Input, computed, inject, signal } from '@angular/core'; import { hlm } from '@spartan-ng/ui-core'; +import { BrnTabsTriggerDirective } from '@spartan-ng/ui-tabs-brain'; import { ClassValue } from 'clsx'; @Directive({ @@ -8,14 +9,21 @@ import { ClassValue } from 'clsx'; host: { '[class]': '_computedClass()', }, + hostDirectives: [BrnTabsTriggerDirective], }) export class HlmTabsTriggerDirective { + private readonly _brn = inject(BrnTabsTriggerDirective); private readonly _userCls = signal(''); @Input() set class(userCls: ClassValue) { this._userCls.set(userCls); } + @Input('hlmTabsTrigger') + set triggerFor(key: string) { + this._brn?.setTriggerFor(key); + } + protected _computedClass = computed(() => this._generateClass()); private _generateClass() { return hlm( diff --git a/libs/ui/tabs/tabs.stories.ts b/libs/ui/tabs/tabs.stories.ts index 393b88052..917f35193 100644 --- a/libs/ui/tabs/tabs.stories.ts +++ b/libs/ui/tabs/tabs.stories.ts @@ -44,11 +44,11 @@ export const Default: Story = { props: { activationMode }, template: ` - - - + + + -
+

Account

@@ -69,7 +69,7 @@ export const Default: Story = {
-
+

Password

@@ -104,12 +104,12 @@ export const Vertical: Story = { template: ` - - - - + + + + -
+

Account

@@ -130,7 +130,7 @@ export const Vertical: Story = {
-
+

Password

@@ -151,7 +151,7 @@ export const Vertical: Story = {
-
+

Delete Account

@@ -168,3 +168,26 @@ export const Vertical: Story = { `, }), }; + +export const BrnOnly: Story = { + args: { + activationMode: 'automatic', + }, + render: ({ activationMode }) => ({ + props: { activationMode }, + template: ` + + + + + +
+ Account content +
+
+ Password content +
+
+`, + }), +}; From ce57ec5a3f1e42a57fe560be9caa3fa9eeb391ca Mon Sep 17 00:00:00 2001 From: elite-benni Date: Tue, 12 Dec 2023 21:10:01 +0100 Subject: [PATCH 2/4] refactor(tabs): tabs brn-taps.component is a directive, brn-taps-list.component is a directive --- .../(tabs)/tabs--vertical.preview.ts | 20 ++---- .../components/(tabs)/tabs.preview.ts | 53 ++++++--------- .../app/src/app/shared/code/code.component.ts | 19 +----- .../src/app/shared/layout/tabs.component.ts | 15 +++-- libs/ui/tabs/brain/src/index.ts | 12 ++-- .../src/lib/brn-tabs-content.directive.ts | 4 +- ...omponent.ts => brn-tabs-list.directive.ts} | 34 ++-------- .../src/lib/brn-tabs-trigger.directive.ts | 4 +- ...abs.component.ts => brn-tabs.directive.ts} | 13 ++-- .../src/lib/hlm-tabs-content.directive.ts | 1 - .../helm/src/lib/hlm-tabs-list.directive.ts | 4 +- libs/ui/tabs/tabs.stories.ts | 64 +++++++++---------- 12 files changed, 88 insertions(+), 155 deletions(-) rename libs/ui/tabs/brain/src/lib/{brn-tabs-list.component.ts => brn-tabs-list.directive.ts} (73%) rename libs/ui/tabs/brain/src/lib/{brn-tabs.component.ts => brn-tabs.directive.ts} (86%) diff --git a/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts b/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts index 0380cf919..0b0c8a708 100644 --- a/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts +++ b/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts @@ -11,22 +11,14 @@ import { } from '@spartan-ng/ui-card-helm'; import { HlmInputDirective } from '@spartan-ng/ui-input-helm'; import { HlmLabelDirective } from '@spartan-ng/ui-label-helm'; -import { - BrnTabsComponent, - BrnTabsContentDirective, - BrnTabsListComponent, - BrnTabsTriggerDirective, -} from '@spartan-ng/ui-tabs-brain'; +import { BrnTabsDirective } from '@spartan-ng/ui-tabs-brain'; import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective } from '@spartan-ng/ui-tabs-helm'; @Component({ selector: 'spartan-tabs-vertical', standalone: true, imports: [ - BrnTabsComponent, - BrnTabsListComponent, - BrnTabsTriggerDirective, - BrnTabsContentDirective, + BrnTabsDirective, HlmTabsListDirective, HlmTabsTriggerDirective, @@ -48,12 +40,12 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective class: 'block w-full max-w-lg min-h-[400px]', }, template: ` - - +
+
- +
@@ -107,7 +99,7 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective
- +
`, }) export class TabsVerticalPreviewComponent {} diff --git a/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts b/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts index 43f2c26bb..ad38928e2 100644 --- a/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts +++ b/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts @@ -1,5 +1,4 @@ import { Component } from '@angular/core'; -import { HlmBadgeDirective } from '@spartan-ng/ui-badge-helm'; import { HlmButtonDirective } from '@spartan-ng/ui-button-helm'; import { HlmCardContentDirective, @@ -11,22 +10,14 @@ import { } from '@spartan-ng/ui-card-helm'; import { HlmInputDirective } from '@spartan-ng/ui-input-helm'; import { HlmLabelDirective } from '@spartan-ng/ui-label-helm'; -import { - BrnTabsComponent, - BrnTabsContentDirective, - BrnTabsListComponent, - BrnTabsTriggerDirective, -} from '@spartan-ng/ui-tabs-brain'; +import { BrnTabsDirective } from '@spartan-ng/ui-tabs-brain'; import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective } from '@spartan-ng/ui-tabs-helm'; @Component({ selector: 'spartan-tabs-preview', standalone: true, imports: [ - BrnTabsComponent, - BrnTabsListComponent, - BrnTabsTriggerDirective, - BrnTabsContentDirective, + BrnTabsDirective, HlmTabsListDirective, HlmTabsTriggerDirective, @@ -42,17 +33,16 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective HlmLabelDirective, HlmInputDirective, HlmButtonDirective, - HlmBadgeDirective, ], host: { class: 'block w-full max-w-lg', }, template: ` - - +
+
- +
@@ -95,14 +85,13 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective
- +
`, }) export class TabsPreviewComponent {} export const defaultCode = ` import { Component } from '@angular/core'; -import { HlmBadgeDirective } from '@spartan-ng/ui-badge-helm'; import { HlmButtonDirective } from '@spartan-ng/ui-button-helm'; import { HlmCardContentDirective, @@ -115,9 +104,9 @@ import { import { HlmInputDirective } from '@spartan-ng/ui-input-helm'; import { HlmLabelDirective } from '@spartan-ng/ui-label-helm'; import { - BrnTabsComponent, + BrnTabsDirective, BrnTabsContentDirective, - BrnTabsListComponent, + BrnTabsListDirective, BrnTabsTriggerDirective, } from '@spartan-ng/ui-tabs-brain'; import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective } from '@spartan-ng/ui-tabs-helm'; @@ -126,10 +115,7 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective selector: 'spartan-tabs-preview', standalone: true, imports: [ - BrnTabsComponent, - BrnTabsListComponent, - BrnTabsTriggerDirective, - BrnTabsContentDirective, + BrnTabsDirective, HlmTabsListDirective, HlmTabsTriggerDirective, @@ -145,17 +131,16 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective HlmLabelDirective, HlmInputDirective, HlmButtonDirective, - HlmBadgeDirective, ], host: { class: 'block w-full max-w-lg', }, template: \` - - +
+
- +
@@ -198,7 +183,7 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective
- +
\`, }) export class TabsPreviewComponent {} @@ -207,24 +192,24 @@ export class TabsPreviewComponent {} export const defaultImports = ` import { - BrnTabsComponent, + BrnTabsDirective, BrnTabsContentDirective, - BrnTabsListComponent, + BrnTabsListDirective, BrnTabsTriggerDirective, } from '@spartan-ng/ui-tabs-brain'; import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective } from '@spartan-ng/ui-tabs-helm'; `; export const defaultSkeleton = ` - - +
+
- +
Make your account here
Change your password here
- +
`; diff --git a/apps/app/src/app/shared/code/code.component.ts b/apps/app/src/app/shared/code/code.component.ts index 4baa854bc..f92448b46 100644 --- a/apps/app/src/app/shared/code/code.component.ts +++ b/apps/app/src/app/shared/code/code.component.ts @@ -1,11 +1,4 @@ import { booleanAttribute, Component, inject, Input, ViewEncapsulation } from '@angular/core'; -import { - BrnTabsComponent, - BrnTabsContentDirective, - BrnTabsListComponent, - BrnTabsTriggerDirective, -} from '@spartan-ng/ui-tabs-brain'; -import { HlmTabsContentDirective } from '@spartan-ng/ui-tabs-helm'; import { marked } from 'marked'; import { gfmHeadingId } from 'marked-gfm-heading-id'; import { markedHighlight } from 'marked-highlight'; @@ -30,17 +23,7 @@ declare const Prism: typeof import('prismjs'); @Component({ selector: 'spartan-code', standalone: true, - imports: [ - BrnTabsComponent, - BrnTabsListComponent, - BrnTabsTriggerDirective, - HlmTabsContentDirective, - BrnTabsContentDirective, - HlmScrollAreaComponent, - HlmButtonDirective, - HlmIconComponent, - NgIf, - ], + imports: [HlmScrollAreaComponent, HlmButtonDirective, HlmIconComponent, NgIf], providers: [provideIcons({ radixClipboard, radixCheck })], host: { class: 'spartan-scroll relative block font-mono rounded-md text-sm text-white bg-zinc-950 dark:bg-zinc-900', diff --git a/apps/app/src/app/shared/layout/tabs.component.ts b/apps/app/src/app/shared/layout/tabs.component.ts index b14892901..303c741b5 100644 --- a/apps/app/src/app/shared/layout/tabs.component.ts +++ b/apps/app/src/app/shared/layout/tabs.component.ts @@ -1,8 +1,8 @@ import { Component, Input } from '@angular/core'; import { - BrnTabsComponent, BrnTabsContentDirective, - BrnTabsListComponent, + BrnTabsDirective, + BrnTabsListDirective, BrnTabsTriggerDirective, } from '@spartan-ng/ui-tabs-brain'; @@ -13,26 +13,27 @@ const tabContent = @Component({ selector: 'spartan-tabs', standalone: true, - imports: [BrnTabsComponent, BrnTabsListComponent, BrnTabsTriggerDirective, BrnTabsContentDirective], + imports: [BrnTabsDirective, BrnTabsListDirective, BrnTabsTriggerDirective, BrnTabsContentDirective], host: { class: 'block', }, template: ` - - +
- +
-
+
`, }) export class TabsComponent { diff --git a/libs/ui/tabs/brain/src/index.ts b/libs/ui/tabs/brain/src/index.ts index 9a7643d3d..7f2ab8b11 100644 --- a/libs/ui/tabs/brain/src/index.ts +++ b/libs/ui/tabs/brain/src/index.ts @@ -1,18 +1,18 @@ import { NgModule } from '@angular/core'; import { BrnTabsContentDirective } from './lib/brn-tabs-content.directive'; -import { BrnTabsListComponent } from './lib/brn-tabs-list.component'; +import { BrnTabsListDirective } from './lib/brn-tabs-list.directive'; import { BrnTabsTriggerDirective } from './lib/brn-tabs-trigger.directive'; -import { BrnTabsComponent } from './lib/brn-tabs.component'; +import { BrnTabsDirective } from './lib/brn-tabs.directive'; export * from './lib/brn-tabs-content.directive'; -export * from './lib/brn-tabs-list.component'; +export * from './lib/brn-tabs-list.directive'; export * from './lib/brn-tabs-trigger.directive'; -export * from './lib/brn-tabs.component'; +export * from './lib/brn-tabs.directive'; export const BrnTabsImports = [ - BrnTabsComponent, - BrnTabsListComponent, + BrnTabsDirective, + BrnTabsListDirective, BrnTabsTriggerDirective, BrnTabsContentDirective, ] as const; diff --git a/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts b/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts index 263ef8248..c8951be82 100644 --- a/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts +++ b/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts @@ -1,5 +1,5 @@ import { computed, Directive, ElementRef, inject, Input } from '@angular/core'; -import { BrnTabsComponent } from './brn-tabs.component'; +import { BrnTabsDirective } from './brn-tabs.directive'; @Directive({ selector: '[brnTabsContent]', @@ -13,7 +13,7 @@ import { BrnTabsComponent } from './brn-tabs.component'; }, }) export class BrnTabsContentDirective { - private _root = inject(BrnTabsComponent); + private _root = inject(BrnTabsDirective); private _elementRef = inject(ElementRef); private _key: string | undefined; diff --git a/libs/ui/tabs/brain/src/lib/brn-tabs-list.component.ts b/libs/ui/tabs/brain/src/lib/brn-tabs-list.directive.ts similarity index 73% rename from libs/ui/tabs/brain/src/lib/brn-tabs-list.component.ts rename to libs/ui/tabs/brain/src/lib/brn-tabs-list.directive.ts index d3b9f68fb..08301a0d6 100644 --- a/libs/ui/tabs/brain/src/lib/brn-tabs-list.component.ts +++ b/libs/ui/tabs/brain/src/lib/brn-tabs-list.directive.ts @@ -1,37 +1,21 @@ import { FocusKeyManager } from '@angular/cdk/a11y'; -import { - AfterContentInit, - ChangeDetectionStrategy, - Component, - ContentChildren, - inject, - Input, - QueryList, - signal, - ViewEncapsulation, -} from '@angular/core'; +import { AfterContentInit, ContentChildren, Directive, inject, QueryList } from '@angular/core'; import { rxHostListener } from '@spartan-ng/ui-core'; import { take } from 'rxjs'; import { BrnTabsTriggerDirective } from './brn-tabs-trigger.directive'; -import { BrnTabsComponent } from './brn-tabs.component'; +import { BrnTabsDirective } from './brn-tabs.directive'; -@Component({ - selector: 'brn-tabs-list', +@Directive({ + selector: '[brnTabsList]', standalone: true, - template: ` - - `, host: { role: 'tablist', '[attr.aria-orientation]': '_orientation()', '[attr.data-orientation]': '_orientation()', - '[attr.aria-label]': '_ariaLabel()', }, - changeDetection: ChangeDetectionStrategy.OnPush, - encapsulation: ViewEncapsulation.None, }) -export class BrnTabsListComponent implements AfterContentInit { - private _root = inject(BrnTabsComponent); +export class BrnTabsListDirective implements AfterContentInit { + private _root = inject(BrnTabsDirective); protected readonly _orientation = this._root.$orientation; private readonly _direction = this._root.$direction; @@ -41,12 +25,6 @@ export class BrnTabsListComponent implements AfterContentInit { private _keyManager?: FocusKeyManager; - protected readonly _ariaLabel = signal(undefined); - @Input('aria-label') - set ariaLabel(value: string | undefined) { - this._ariaLabel.set(value); - } - @ContentChildren(BrnTabsTriggerDirective, { descendants: true }) public triggers?: QueryList; diff --git a/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts b/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts index fa7a11864..d9a081c1c 100644 --- a/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts +++ b/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts @@ -1,5 +1,5 @@ import { computed, Directive, ElementRef, inject, Input } from '@angular/core'; -import { BrnTabsComponent } from './brn-tabs.component'; +import { BrnTabsDirective } from './brn-tabs.directive'; @Directive({ selector: 'button[brnTabsTrigger]', @@ -18,7 +18,7 @@ import { BrnTabsComponent } from './brn-tabs.component'; }, }) export class BrnTabsTriggerDirective { - private _root = inject(BrnTabsComponent); + private _root = inject(BrnTabsDirective); private _elementRef = inject(ElementRef); private _key: string | undefined; diff --git a/libs/ui/tabs/brain/src/lib/brn-tabs.component.ts b/libs/ui/tabs/brain/src/lib/brn-tabs.directive.ts similarity index 86% rename from libs/ui/tabs/brain/src/lib/brn-tabs.component.ts rename to libs/ui/tabs/brain/src/lib/brn-tabs.directive.ts index 51c599caf..1272b7499 100644 --- a/libs/ui/tabs/brain/src/lib/brn-tabs.component.ts +++ b/libs/ui/tabs/brain/src/lib/brn-tabs.directive.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, Input, signal, ViewEncapsulation } from '@angular/core'; +import { Directive, Input, signal } from '@angular/core'; import { BrnTabsContentDirective } from './brn-tabs-content.directive'; import { BrnTabsTriggerDirective } from './brn-tabs-trigger.directive'; @@ -6,20 +6,15 @@ export type BrnTabsOrientation = 'horizontal' | 'vertical'; export type BrnTabsDirection = 'ltr' | 'rtl'; export type BrnActivationMode = 'automatic' | 'manual'; -@Component({ - selector: 'brn-tabs', +@Directive({ + selector: '[brnTabs]', standalone: true, - template: ` - - `, host: { '[attr.data-orientation]': '_orientation()', '[attr.dir]': '_direction()', }, - changeDetection: ChangeDetectionStrategy.OnPush, - encapsulation: ViewEncapsulation.None, }) -export class BrnTabsComponent { +export class BrnTabsDirective { protected readonly _orientation = signal('horizontal'); @Input() set orientation(value: BrnTabsOrientation) { diff --git a/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts b/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts index d57304bfe..fa331b847 100644 --- a/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts +++ b/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts @@ -21,7 +21,6 @@ export class HlmTabsContentDirective { @Input('hlmTabsContent') set contentFor(key: string) { - console.log('contentFor', key); this._brn?.setContentFor(key); } diff --git a/libs/ui/tabs/helm/src/lib/hlm-tabs-list.directive.ts b/libs/ui/tabs/helm/src/lib/hlm-tabs-list.directive.ts index 6c6831cd6..29fab3638 100644 --- a/libs/ui/tabs/helm/src/lib/hlm-tabs-list.directive.ts +++ b/libs/ui/tabs/helm/src/lib/hlm-tabs-list.directive.ts @@ -1,5 +1,6 @@ import { computed, Directive, Input, signal } from '@angular/core'; import { hlm } from '@spartan-ng/ui-core'; +import { BrnTabsListDirective } from '@spartan-ng/ui-tabs-brain'; import { cva, VariantProps } from 'class-variance-authority'; import { ClassValue } from 'clsx'; @@ -20,8 +21,9 @@ export const listVariants = cva( type ListVariants = VariantProps; @Directive({ - selector: '[hlmTabsList], brn-tabs-list[hlm]', + selector: '[hlmTabsList]', standalone: true, + hostDirectives: [BrnTabsListDirective], host: { '[class]': '_computedClass()', }, diff --git a/libs/ui/tabs/tabs.stories.ts b/libs/ui/tabs/tabs.stories.ts index 917f35193..72370e179 100644 --- a/libs/ui/tabs/tabs.stories.ts +++ b/libs/ui/tabs/tabs.stories.ts @@ -1,5 +1,4 @@ import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; -import { HlmBadgeDirective } from '../badge/helm/src'; import { HlmButtonDirective } from '../button/helm/src'; import { HlmCardImports } from '../card/helm/src'; import { HlmInputDirective } from '../input/helm/src'; @@ -28,7 +27,6 @@ const meta: Meta = { HlmLabelDirective, HlmInputDirective, HlmButtonDirective, - HlmBadgeDirective, ], }), ], @@ -43,11 +41,11 @@ export const Default: Story = { render: ({ activationMode }) => ({ props: { activationMode }, template: ` - - +
+
- +
@@ -70,27 +68,27 @@ export const Default: Story = {
-
-
-

Password

-

- Change your password here. After saving, you'll be logged out. +

+
+

Password

+

+ Change your password here. After saving, you'll be logged out. +

+
+

+ +

-
-

- - -

-
- -
-
-
- +
+ +
+
+
+
`, }), }; @@ -102,13 +100,13 @@ export const Vertical: Story = { render: ({ activationMode }) => ({ props: { activationMode }, template: ` - - +
- +
@@ -164,7 +162,7 @@ export const Vertical: Story = {
-
+
`, }), }; @@ -176,18 +174,18 @@ export const BrnOnly: Story = { render: ({ activationMode }) => ({ props: { activationMode }, template: ` - - +
+
- +
Account content
Password content
- +
`, }), }; From 7fad230a4cc87ade078b4e34e9eafd3f100e7fe1 Mon Sep 17 00:00:00 2001 From: elite-benni Date: Tue, 12 Dec 2023 21:49:50 +0100 Subject: [PATCH 3/4] refactor(tabs): extra function for setting contentfor and triggerFor is not needed --- libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts | 4 ---- libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts | 4 ---- libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts | 4 +++- libs/ui/tabs/helm/src/lib/hlm-tabs-trigger.directive.ts | 4 +++- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts b/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts index c8951be82..725aae2a8 100644 --- a/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts +++ b/libs/ui/tabs/brain/src/lib/brn-tabs-content.directive.ts @@ -29,10 +29,6 @@ export class BrnTabsContentDirective { this._root.registerContent(key, this); } - public setContentFor(key: string) { - this.contentFor = key; - } - public focus() { this._elementRef.nativeElement.focus(); } diff --git a/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts b/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts index d9a081c1c..4a53115df 100644 --- a/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts +++ b/libs/ui/tabs/brain/src/lib/brn-tabs-trigger.directive.ts @@ -37,10 +37,6 @@ export class BrnTabsTriggerDirective { @Input() public disabled = false; - public setTriggerFor(key: string) { - this.triggerFor = key; - } - public focus() { this._elementRef.nativeElement.focus(); if (this._root.$activationMode() === 'automatic') { diff --git a/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts b/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts index fa331b847..02ae0f3a5 100644 --- a/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts +++ b/libs/ui/tabs/helm/src/lib/hlm-tabs-content.directive.ts @@ -21,7 +21,9 @@ export class HlmTabsContentDirective { @Input('hlmTabsContent') set contentFor(key: string) { - this._brn?.setContentFor(key); + if (this._brn) { + this._brn.contentFor = key; + } } protected _computedClass = computed(() => this._generateClass()); diff --git a/libs/ui/tabs/helm/src/lib/hlm-tabs-trigger.directive.ts b/libs/ui/tabs/helm/src/lib/hlm-tabs-trigger.directive.ts index 89bc60fa3..505d25bcd 100644 --- a/libs/ui/tabs/helm/src/lib/hlm-tabs-trigger.directive.ts +++ b/libs/ui/tabs/helm/src/lib/hlm-tabs-trigger.directive.ts @@ -21,7 +21,9 @@ export class HlmTabsTriggerDirective { @Input('hlmTabsTrigger') set triggerFor(key: string) { - this._brn?.setTriggerFor(key); + if (this._brn) { + this._brn.triggerFor = key; + } } protected _computedClass = computed(() => this._generateClass()); From 62b2d695e1d4bc6196413bfd6c6b515e576b98e2 Mon Sep 17 00:00:00 2001 From: elite-benni Date: Tue, 12 Dec 2023 23:39:52 +0100 Subject: [PATCH 4/4] refactor(tabs): brn-tabs value is set by Input brnTabs --- .../components/(tabs)/tabs--vertical.preview.ts | 2 +- .../pages/(components)/components/(tabs)/tabs.preview.ts | 6 +++--- apps/app/src/app/shared/layout/tabs.component.ts | 2 +- libs/ui/tabs/brain/src/lib/brn-tabs.directive.ts | 2 +- libs/ui/tabs/tabs.stories.ts | 7 +++---- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts b/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts index 0b0c8a708..c930e71d7 100644 --- a/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts +++ b/apps/app/src/app/pages/(components)/components/(tabs)/tabs--vertical.preview.ts @@ -40,7 +40,7 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective class: 'block w-full max-w-lg min-h-[400px]', }, template: ` -
+
diff --git a/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts b/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts index ad38928e2..57f07bc46 100644 --- a/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts +++ b/apps/app/src/app/pages/(components)/components/(tabs)/tabs.preview.ts @@ -38,7 +38,7 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective class: 'block w-full max-w-lg', }, template: ` -
+
@@ -136,7 +136,7 @@ import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective class: 'block w-full max-w-lg', }, template: \` -
+
@@ -200,7 +200,7 @@ import { import { HlmTabsContentDirective, HlmTabsListDirective, HlmTabsTriggerDirective } from '@spartan-ng/ui-tabs-helm'; `; export const defaultSkeleton = ` -
+
diff --git a/apps/app/src/app/shared/layout/tabs.component.ts b/apps/app/src/app/shared/layout/tabs.component.ts index 303c741b5..616d81b0f 100644 --- a/apps/app/src/app/shared/layout/tabs.component.ts +++ b/apps/app/src/app/shared/layout/tabs.component.ts @@ -18,7 +18,7 @@ const tabContent = class: 'block', }, template: ` -
+
(undefined); - @Input() + @Input('brnTabs') set value(value: string) { this._value.set(value); } diff --git a/libs/ui/tabs/tabs.stories.ts b/libs/ui/tabs/tabs.stories.ts index 72370e179..b5e27b2a5 100644 --- a/libs/ui/tabs/tabs.stories.ts +++ b/libs/ui/tabs/tabs.stories.ts @@ -41,7 +41,7 @@ export const Default: Story = { render: ({ activationMode }) => ({ props: { activationMode }, template: ` -
+
@@ -100,8 +100,7 @@ export const Vertical: Story = { render: ({ activationMode }) => ({ props: { activationMode }, template: ` -
+
@@ -174,7 +173,7 @@ export const BrnOnly: Story = { render: ({ activationMode }) => ({ props: { activationMode }, template: ` -
+