From d4864d41ceedef7752f3aeafe3f3a942c427ab27 Mon Sep 17 00:00:00 2001 From: Ashley Hunter <20795331+ashley-hunter@users.noreply.github.com> Date: Thu, 9 Jan 2025 22:05:29 +0000 Subject: [PATCH 1/5] fix: code quality linting improvements --- libs/ui/breadcrumb/helm/eslint.config.js | 62 ++++++++----------- libs/ui/carousel/helm/eslint.config.js | 2 +- .../src/lib/hlm-carousel-next.component.ts | 1 - .../lib/hlm-carousel-previous.component.ts | 1 - libs/ui/checkbox/helm/src/index.ts | 4 +- .../lib/hlm-checkbox-checkicon.component.ts | 35 ----------- .../helm/src/lib/hlm-checkbox.component.ts | 51 ++++++++------- .../dialog/helm/src/lib/hlm-dialog.service.ts | 5 +- .../icon/helm/src/lib/hlm-icon.directive.ts | 7 +-- libs/ui/sonner/helm/jest.config.ts | 1 - .../helm/src/lib/hlm-switch.component.ts | 13 ++-- 11 files changed, 68 insertions(+), 114 deletions(-) delete mode 100644 libs/ui/checkbox/helm/src/lib/hlm-checkbox-checkicon.component.ts diff --git a/libs/ui/breadcrumb/helm/eslint.config.js b/libs/ui/breadcrumb/helm/eslint.config.js index 03151f89f..10f4f18c3 100644 --- a/libs/ui/breadcrumb/helm/eslint.config.js +++ b/libs/ui/breadcrumb/helm/eslint.config.js @@ -1,42 +1,34 @@ -const { FlatCompat } = require('@eslint/eslintrc'); +const nx = require('@nx/eslint-plugin'); const baseConfig = require('../../../../eslint.config.cjs'); -const js = require('@eslint/js'); - -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, -}); module.exports = [ ...baseConfig, - ...compat - .config({ extends: ['plugin:@nx/angular', 'plugin:@angular-eslint/template/process-inline-templates'] }) - .map((config) => ({ - ...config, - files: ['**/*.ts'], - rules: { - '@angular-eslint/no-host-metadata-property': 0, - '@angular-eslint/directive-selector': [ - 'error', - { - type: 'attribute', - prefix: 'hlm', - style: 'camelCase', - }, - ], - '@angular-eslint/component-selector': [ - 'error', - { - type: 'element', - prefix: 'hlm', - style: 'kebab-case', - }, - ], - }, - })), - ...compat.config({ extends: ['plugin:@nx/angular-template'] }).map((config) => ({ - ...config, + ...nx.configs['flat/angular'], + ...nx.configs['flat/angular-template'], + { + files: ['**/*.ts'], + rules: { + '@angular-eslint/directive-selector': [ + 'error', + { + type: 'attribute', + prefix: 'hlm', + style: 'camelCase', + }, + ], + '@angular-eslint/component-selector': [ + 'error', + { + type: 'element', + prefix: 'hlm', + style: 'kebab-case', + }, + ], + }, + }, + { files: ['**/*.html'], + // Override or add rules here rules: {}, - })), + }, ]; diff --git a/libs/ui/carousel/helm/eslint.config.js b/libs/ui/carousel/helm/eslint.config.js index 10f4f18c3..6bce1baaf 100644 --- a/libs/ui/carousel/helm/eslint.config.js +++ b/libs/ui/carousel/helm/eslint.config.js @@ -19,7 +19,7 @@ module.exports = [ '@angular-eslint/component-selector': [ 'error', { - type: 'element', + type: ['attribute', 'element'], prefix: 'hlm', style: 'kebab-case', }, diff --git a/libs/ui/carousel/helm/src/lib/hlm-carousel-next.component.ts b/libs/ui/carousel/helm/src/lib/hlm-carousel-next.component.ts index 12fd9bc7e..809a3a4e8 100644 --- a/libs/ui/carousel/helm/src/lib/hlm-carousel-next.component.ts +++ b/libs/ui/carousel/helm/src/lib/hlm-carousel-next.component.ts @@ -17,7 +17,6 @@ import type { ClassValue } from 'clsx'; import { HlmCarouselComponent } from './hlm-carousel.component'; @Component({ - // eslint-disable-next-line @angular-eslint/component-selector selector: 'button[hlm-carousel-next], button[hlmCarouselNext]', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/libs/ui/carousel/helm/src/lib/hlm-carousel-previous.component.ts b/libs/ui/carousel/helm/src/lib/hlm-carousel-previous.component.ts index aa0d2e95f..018d957f7 100644 --- a/libs/ui/carousel/helm/src/lib/hlm-carousel-previous.component.ts +++ b/libs/ui/carousel/helm/src/lib/hlm-carousel-previous.component.ts @@ -17,7 +17,6 @@ import type { ClassValue } from 'clsx'; import { HlmCarouselComponent } from './hlm-carousel.component'; @Component({ - // eslint-disable-next-line @angular-eslint/component-selector selector: 'button[hlm-carousel-previous], button[hlmCarouselPrevious]', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/libs/ui/checkbox/helm/src/index.ts b/libs/ui/checkbox/helm/src/index.ts index 18374d9dc..5c4b6df64 100644 --- a/libs/ui/checkbox/helm/src/index.ts +++ b/libs/ui/checkbox/helm/src/index.ts @@ -1,12 +1,10 @@ import { NgModule } from '@angular/core'; -import { HlmCheckboxCheckIconComponent } from './lib/hlm-checkbox-checkicon.component'; import { HlmCheckboxComponent } from './lib/hlm-checkbox.component'; -export * from './lib/hlm-checkbox-checkicon.component'; export * from './lib/hlm-checkbox.component'; -export const HlmCheckboxImports = [HlmCheckboxComponent, HlmCheckboxCheckIconComponent] as const; +export const HlmCheckboxImports = [HlmCheckboxComponent] as const; @NgModule({ imports: [...HlmCheckboxImports], exports: [...HlmCheckboxImports], diff --git a/libs/ui/checkbox/helm/src/lib/hlm-checkbox-checkicon.component.ts b/libs/ui/checkbox/helm/src/lib/hlm-checkbox-checkicon.component.ts deleted file mode 100644 index 0a67b0bb3..000000000 --- a/libs/ui/checkbox/helm/src/lib/hlm-checkbox-checkicon.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Component, computed, inject, input } from '@angular/core'; -import { NgIcon, provideIcons } from '@ng-icons/core'; -import { lucideCheck } from '@ng-icons/lucide'; -import { BrnCheckboxComponent } from '@spartan-ng/brain/checkbox'; -import { hlm } from '@spartan-ng/brain/core'; -import { HlmIconDirective } from '@spartan-ng/ui-icon-helm'; -import type { ClassValue } from 'clsx'; - -@Component({ - selector: 'hlm-checkbox-checkicon', - standalone: true, - imports: [NgIcon, HlmIconDirective], - providers: [provideIcons({ lucideCheck })], - host: { - '[class]': '_computedClass()', - }, - template: ` - - `, -}) -export class HlmCheckboxCheckIconComponent { - private readonly _brnCheckbox = inject(BrnCheckboxComponent); - protected _checked = this._brnCheckbox?.isChecked; - public readonly userClass = input('', { alias: 'class' }); - - public readonly iconName = input('lucideCheck'); - - protected _computedClass = computed(() => - hlm( - 'h-4 w-4 leading-none group-data-[state=unchecked]:opacity-0', - this._checked() === 'indeterminate' ? 'opacity-50' : '', - this.userClass(), - ), - ); -} diff --git a/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts b/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts index c4fe254fe..ad6b49ff0 100644 --- a/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts +++ b/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts @@ -1,9 +1,12 @@ import { Component, booleanAttribute, computed, forwardRef, input, model, output, signal } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { NgIcon, provideIcons } from '@ng-icons/core'; +import { lucideCheck } from '@ng-icons/lucide'; import { BrnCheckboxComponent } from '@spartan-ng/brain/checkbox'; import { hlm } from '@spartan-ng/brain/core'; +import { ChangeFn, TouchFn } from '@spartan-ng/brain/forms'; +import { HlmIconDirective } from '@spartan-ng/ui-icon-helm'; import type { ClassValue } from 'clsx'; -import { HlmCheckboxCheckIconComponent } from './hlm-checkbox-checkicon.component'; export const HLM_CHECKBOX_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, @@ -14,7 +17,7 @@ export const HLM_CHECKBOX_VALUE_ACCESSOR = { @Component({ selector: 'hlm-checkbox', standalone: true, - imports: [BrnCheckboxComponent, HlmCheckboxCheckIconComponent], + imports: [BrnCheckboxComponent, NgIcon, HlmIconDirective], template: ` - + `, host: { @@ -40,10 +43,12 @@ export const HLM_CHECKBOX_VALUE_ACCESSOR = { '[attr.aria-describedby]': 'null', }, providers: [HLM_CHECKBOX_VALUE_ACCESSOR], + viewProviders: [provideIcons({ lucideCheck })], }) export class HlmCheckboxComponent { public readonly userClass = input('', { alias: 'class' }); - protected _computedClass = computed(() => + + protected readonly _computedClass = computed(() => hlm( 'group inline-flex border border-foreground shrink-0 cursor-pointer items-center rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring' + ' focus-visible:ring-offset-2 focus-visible:ring-offset-background data-[state=checked]:text-background data-[state=checked]:bg-primary data-[state=unchecked]:bg-background', @@ -52,6 +57,10 @@ export class HlmCheckboxComponent { ), ); + protected readonly _computedIconClass = computed(() => + hlm('leading-none group-data-[state=unchecked]:opacity-0', this.checked() === 'indeterminate' ? 'opacity-50' : ''), + ); + /** Used to set the id on the underlying brn element. */ public readonly id = input(null); @@ -64,50 +73,46 @@ export class HlmCheckboxComponent { /** Used to set the aria-describedby attribute on the underlying brn element. */ public readonly ariaDescribedby = input(null, { alias: 'aria-describedby' }); - public readonly checked = model(false); + /** The checked state of the checkbox. */ + public readonly checked = model(false); + /** The name attribute of the checkbox. */ public readonly name = input(null); + + /** Whether the checkbox is required. */ public readonly required = input(false, { transform: booleanAttribute }); + /** Whether the checkbox is disabled. */ public readonly disabled = input(false, { transform: booleanAttribute }); protected readonly state = computed(() => ({ disabled: signal(this.disabled()), })); - // icon inputs - public readonly checkIconName = input('lucideCheck'); - public readonly checkIconClass = input(''); - public readonly changed = output(); + protected _onChange?: ChangeFn; + protected _onTouched?: TouchFn; + protected _handleChange(): void { if (this.state().disabled()) return; const previousChecked = this.checked(); this.checked.set(previousChecked === 'indeterminate' ? true : !previousChecked); - this._onChange(!previousChecked); + this._onChange?.(!previousChecked); this.changed.emit(!previousChecked); } /** CONROL VALUE ACCESSOR */ - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - writeValue(value: any): void { + writeValue(value: CheckboxValue): void { this.checked.set(!!value); } - // eslint-disable-next-line @typescript-eslint/no-empty-function,,@typescript-eslint/no-explicit-any - protected _onChange = (_: any) => {}; - // eslint-disable-next-line @typescript-eslint/no-empty-function - protected _onTouched = () => {}; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - registerOnChange(fn: any): void { + registerOnChange(fn: ChangeFn): void { this._onChange = fn; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - registerOnTouched(fn: any): void { + registerOnTouched(fn: TouchFn): void { this._onTouched = fn; } @@ -115,3 +120,5 @@ export class HlmCheckboxComponent { this.state().disabled.set(isDisabled); } } + +type CheckboxValue = boolean | 'indeterminate'; diff --git a/libs/ui/dialog/helm/src/lib/hlm-dialog.service.ts b/libs/ui/dialog/helm/src/lib/hlm-dialog.service.ts index eb481d3e4..5c0816170 100644 --- a/libs/ui/dialog/helm/src/lib/hlm-dialog.service.ts +++ b/libs/ui/dialog/helm/src/lib/hlm-dialog.service.ts @@ -9,8 +9,7 @@ import { import { HlmDialogContentComponent } from './hlm-dialog-content.component'; import { hlmDialogOverlayClass } from './hlm-dialog-overlay.directive'; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type HlmDialogOptions = BrnDialogOptions & { +export type HlmDialogOptions = BrnDialogOptions & { contentClass?: string; context?: DialogContext; }; @@ -28,7 +27,7 @@ export class HlmDialogService { ...(options ?? {}), backdropClass: cssClassesToArray(`${hlmDialogOverlayClass} ${options?.backdropClass ?? ''}`), - context: { ...options?.context, $component: component, $dynamicComponentClass: options?.contentClass }, + context: { ...(options?.context ?? {}), $component: component, $dynamicComponentClass: options?.contentClass }, }; return this._brnDialogService.open(HlmDialogContentComponent, undefined, mergedOptions.context, mergedOptions); diff --git a/libs/ui/icon/helm/src/lib/hlm-icon.directive.ts b/libs/ui/icon/helm/src/lib/hlm-icon.directive.ts index deef64a16..ce0de33ac 100644 --- a/libs/ui/icon/helm/src/lib/hlm-icon.directive.ts +++ b/libs/ui/icon/helm/src/lib/hlm-icon.directive.ts @@ -1,12 +1,7 @@ import { Directive, computed, input } from '@angular/core'; import { injectHlmIconConfig } from './hlm-icon.token'; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const DEFINED_SIZES = ['xs', 'sm', 'base', 'lg', 'xl', 'none'] as const; - -type DefinedSizes = (typeof DEFINED_SIZES)[number]; - -export type IconSize = DefinedSizes | (Record & string); +export type IconSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl' | 'none' | ({} & string); @Directive({ selector: 'ng-icon[hlm]', diff --git a/libs/ui/sonner/helm/jest.config.ts b/libs/ui/sonner/helm/jest.config.ts index 0c5a1fd5e..be69bd451 100644 --- a/libs/ui/sonner/helm/jest.config.ts +++ b/libs/ui/sonner/helm/jest.config.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ export default { displayName: 'ui-sonner-helm', preset: '../../../../jest.preset.cjs', diff --git a/libs/ui/switch/helm/src/lib/hlm-switch.component.ts b/libs/ui/switch/helm/src/lib/hlm-switch.component.ts index b1ec70123..2d2a7937f 100644 --- a/libs/ui/switch/helm/src/lib/hlm-switch.component.ts +++ b/libs/ui/switch/helm/src/lib/hlm-switch.component.ts @@ -28,7 +28,7 @@ export const HLM_SWITCH_VALUE_ACCESSOR = { [class]="_computedClass()" [checked]="checked()" (changed)="handleChange($event)" - (touched)="_onTouched()" + (touched)="_onTouched?.()" [disabled]="disabled()" [id]="id()" [aria-label]="ariaLabel()" @@ -50,8 +50,10 @@ export class HlmSwitchComponent { ), ); + /** The checked state of the switch. */ public readonly checked = model(false); + /** The disabled state of the switch. */ public readonly disabled = input(false, { transform: booleanAttribute, }); @@ -68,16 +70,15 @@ export class HlmSwitchComponent { /** Used to set the aria-describedby attribute on the underlying brn element. */ public readonly ariaDescribedby = input(null, { alias: 'aria-describedby' }); + /** Emits when the checked state of the switch changes. */ public readonly changed = output(); - // eslint-disable-next-line @typescript-eslint/no-empty-function - protected _onChange: ChangeFn = () => {}; - // eslint-disable-next-line @typescript-eslint/no-empty-function - protected _onTouched: TouchFn = () => {}; + protected _onChange?: ChangeFn; + protected _onTouched?: TouchFn; protected handleChange(value: boolean): void { this.checked.set(value); - this._onChange(value); + this._onChange?.(value); this.changed.emit(value); } From f1e6679ff810e9059cc206ae0c830d59e289670a Mon Sep 17 00:00:00 2001 From: Ashley Hunter <20795331+ashley-hunter@users.noreply.github.com> Date: Thu, 9 Jan 2025 22:21:02 +0000 Subject: [PATCH 2/5] fix: removing unused imports --- .../(components)/components/(checkbox)/checkbox.preview.ts | 2 +- .../components/(data-table)/data-table.preview.ts | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/app/src/app/pages/(components)/components/(checkbox)/checkbox.preview.ts b/apps/app/src/app/pages/(components)/components/(checkbox)/checkbox.preview.ts index e475454a0..f22c4f12a 100644 --- a/apps/app/src/app/pages/(components)/components/(checkbox)/checkbox.preview.ts +++ b/apps/app/src/app/pages/(components)/components/(checkbox)/checkbox.preview.ts @@ -17,7 +17,7 @@ export class CheckboxPreviewComponent {} export const defaultCode = ` import { Component } from '@angular/core'; -import { HlmCheckboxCheckIconComponent, HlmCheckboxComponent } from '@spartan-ng/ui-checkbox-helm'; +import { HlmCheckboxComponent } from '@spartan-ng/ui-checkbox-helm'; import { HlmLabelDirective } from '@spartan-ng/ui-label-helm'; @Component({ selector: 'spartan-checkbox-preview', diff --git a/apps/app/src/app/pages/(components)/components/(data-table)/data-table.preview.ts b/apps/app/src/app/pages/(components)/components/(data-table)/data-table.preview.ts index 941d1f91a..dba500ac1 100644 --- a/apps/app/src/app/pages/(components)/components/(data-table)/data-table.preview.ts +++ b/apps/app/src/app/pages/(components)/components/(data-table)/data-table.preview.ts @@ -9,7 +9,7 @@ import { BrnMenuTriggerDirective } from '@spartan-ng/brain/menu'; import { BrnSelectModule } from '@spartan-ng/brain/select'; import { BrnTableModule, type PaginatorState, useBrnColumnManager } from '@spartan-ng/brain/table'; import { HlmButtonModule } from '@spartan-ng/ui-button-helm'; -import { HlmCheckboxCheckIconComponent, HlmCheckboxComponent } from '@spartan-ng/ui-checkbox-helm'; +import { HlmCheckboxComponent } from '@spartan-ng/ui-checkbox-helm'; import { HlmIconDirective } from '@spartan-ng/ui-icon-helm'; import { HlmInputDirective } from '@spartan-ng/ui-input-helm'; import { HlmMenuModule } from '@spartan-ng/ui-menu-helm'; @@ -168,7 +168,6 @@ const PAYMENT_DATA: Payment[] = [ HlmIconDirective, HlmInputDirective, - HlmCheckboxCheckIconComponent, HlmCheckboxComponent, BrnSelectModule, @@ -404,7 +403,7 @@ import { toObservable, toSignal } from '@angular/core/rxjs-interop'; import { FormsModule } from '@angular/forms'; import { lucideArrowUpDown, lucideChevronDown, lucideEllipsis } from '@ng-icons/lucide'; import { HlmButtonModule } from '@spartan-ng/ui-button-helm'; -import { HlmCheckboxCheckIconComponent, HlmCheckboxComponent } from '@spartan-ng/ui-checkbox-helm'; +import { HlmCheckboxComponent } from '@spartan-ng/ui-checkbox-helm'; import { HlmIconDirective, provideIcons } from '@spartan-ng/ui-icon-helm'; import { HlmInputDirective } from '@spartan-ng/ui-input-helm'; import { BrnMenuTriggerDirective } from '@spartan-ng/brain/menu'; @@ -565,7 +564,6 @@ const PAYMENT_DATA: Payment[] = [ HlmIconDirective, HlmInputDirective, - HlmCheckboxCheckIconComponent, HlmCheckboxComponent, BrnSelectModule, From 9b078ee9649516561670715cedc64f5a3f52a3c0 Mon Sep 17 00:00:00 2001 From: Ashley Hunter <20795331+ashley-hunter@users.noreply.github.com> Date: Thu, 9 Jan 2025 22:40:48 +0000 Subject: [PATCH 3/5] fix: missing icon class --- libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts b/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts index ad6b49ff0..1924ef443 100644 --- a/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts +++ b/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts @@ -32,7 +32,7 @@ export const HLM_CHECKBOX_VALUE_ACCESSOR = { (changed)="_handleChange()" (touched)="_onTouched?.()" > - + `, host: { From 0a9b67644aecd0892fdef2f670a6c69cb15554c6 Mon Sep 17 00:00:00 2001 From: Ashley Hunter Date: Sun, 12 Jan 2025 12:14:18 +0000 Subject: [PATCH 4/5] fix: using type import Co-authored-by: Ajit Panigrahi --- libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts b/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts index 1924ef443..e81b091b6 100644 --- a/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts +++ b/libs/ui/checkbox/helm/src/lib/hlm-checkbox.component.ts @@ -4,7 +4,7 @@ import { NgIcon, provideIcons } from '@ng-icons/core'; import { lucideCheck } from '@ng-icons/lucide'; import { BrnCheckboxComponent } from '@spartan-ng/brain/checkbox'; import { hlm } from '@spartan-ng/brain/core'; -import { ChangeFn, TouchFn } from '@spartan-ng/brain/forms'; +import type { ChangeFn, TouchFn } from '@spartan-ng/brain/forms'; import { HlmIconDirective } from '@spartan-ng/ui-icon-helm'; import type { ClassValue } from 'clsx'; From d603435a9987b23a9742b9ab1454b56850888b49 Mon Sep 17 00:00:00 2001 From: Ashley Hunter Date: Sun, 12 Jan 2025 21:43:35 +0000 Subject: [PATCH 5/5] refactor: use record Co-authored-by: Ajit Panigrahi --- libs/ui/icon/helm/src/lib/hlm-icon.directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ui/icon/helm/src/lib/hlm-icon.directive.ts b/libs/ui/icon/helm/src/lib/hlm-icon.directive.ts index ce0de33ac..0658c4e07 100644 --- a/libs/ui/icon/helm/src/lib/hlm-icon.directive.ts +++ b/libs/ui/icon/helm/src/lib/hlm-icon.directive.ts @@ -1,7 +1,7 @@ import { Directive, computed, input } from '@angular/core'; import { injectHlmIconConfig } from './hlm-icon.token'; -export type IconSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl' | 'none' | ({} & string); +export type IconSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl' | 'none' | (Record & string); @Directive({ selector: 'ng-icon[hlm]',