From 929763520d0c48daee0fbc9d49a824049caa092d Mon Sep 17 00:00:00 2001 From: Mohammad Javed Date: Sat, 20 Sep 2025 14:22:19 +0530 Subject: [PATCH 1/8] UI(switch): Update switch styles --- projects/ui/src/directives/switch.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/ui/src/directives/switch.ts b/projects/ui/src/directives/switch.ts index 2c63ad3..a432faf 100644 --- a/projects/ui/src/directives/switch.ts +++ b/projects/ui/src/directives/switch.ts @@ -4,8 +4,8 @@ import { NgpSwitch, NgpSwitchThumb } from "ng-primitives/switch"; const switchVariants = tv({ slots: { - switchRoot: 'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors data-[focus-visible]:outline-none data-[focus-visible]:ring-2 data-[focus-visible]:ring-ring data-[focus-visible]:ring-offset-2 data-[focus-visible]:ring-offset-background data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[checked]:bg-primary bg-input', - switchThumb: 'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[checked]:translate-x-5 translate-x-0' + switchRoot: 'peer data-[checked]:bg-primary bg-input data-[focus-visible]:border-ring data-[focus-visible]:ring-ring/50 dark:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none data-[focus-visible]:ring-[3px] data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50', + switchThumb: 'bg-background dark:bg-foreground dark:data-[checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[checked]:translate-x-[calc(100%-2px)] translate-x-0' } }); From 19b90369b97e5c4618fab83be8c3657711894624 Mon Sep 17 00:00:00 2001 From: Mohammad Javed Date: Sun, 21 Sep 2025 15:15:01 +0530 Subject: [PATCH 2/8] fix(alert-dialog): Fix alert dialog overaly click and escape closing issue --- package-lock.json | 148 ++++++++++----------- package.json | 2 +- projects/ui/src/directives/alert-dialog.ts | 8 +- 3 files changed, 79 insertions(+), 79 deletions(-) diff --git a/package-lock.json b/package-lock.json index 897d7e2..57fe32c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "@slateui/theme": "^1.0.0", "@tailwindcss/postcss": "^4.1.11", "express": "^5.1.0", - "ng-primitives": "^0.74.0", + "ng-primitives": "^0.80.0", "ngx-highlightjs": "^14.0.1", "postcss": "^8.5.6", "rxjs": "~7.8.0", @@ -758,9 +758,9 @@ } }, "node_modules/@angular/ssr": { - "version": "20.1.3", - "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-20.1.3.tgz", - "integrity": "sha512-ZXTUlLC6iC4Tl7uY3ACaS5+1JC6bnbByk/y0agnCXjHN/5qogIR44ECQDPlLmPZfC1dZaxF4d0WSge9OZdeu4Q==", + "version": "20.3.2", + "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-20.3.2.tgz", + "integrity": "sha512-IMSl4wUM1297HmAB+iT72hbku3mP7uswV/EoE87oK7txvQExSNEFtO/8NJbgBrdFOLhG0JH+axqfwZo1vfBJAA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1530,6 +1530,16 @@ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, + "node_modules/@inquirer/ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.0.tgz", + "integrity": "sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@inquirer/checkbox": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.0.tgz", @@ -1578,15 +1588,15 @@ } }, "node_modules/@inquirer/core": { - "version": "10.1.15", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.15.tgz", - "integrity": "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.2.tgz", + "integrity": "sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==", "dev": true, "license": "MIT", "dependencies": { + "@inquirer/ansi": "^1.0.0", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", @@ -1606,15 +1616,15 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.15", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.15.tgz", - "integrity": "sha512-wst31XT8DnGOSS4nNJDIklGKnf+8shuauVrWzgKegWUe28zfCftcWZ2vktGdzJgcylWSS2SrDnYUb6alZcwnCQ==", + "version": "4.2.20", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.20.tgz", + "integrity": "sha512-7omh5y5bK672Q+Brk4HBbnHNowOZwrb/78IFXdrEB9PfdxL3GudQyDk8O9vQ188wj3xrEebS2M9n18BjJoI83g==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/type": "^3.0.8", - "external-editor": "^3.1.0" + "@inquirer/core": "^10.2.2", + "@inquirer/external-editor": "^1.0.2", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" @@ -1651,6 +1661,45 @@ } } }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", + "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/@inquirer/figures": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", @@ -4729,9 +4778,9 @@ } }, "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", "dev": true, "license": "MIT" }, @@ -5895,34 +5944,6 @@ "dev": true, "license": "MIT" }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "license": "MIT", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -7354,16 +7375,6 @@ "node": ">=8" } }, - "node_modules/karma/node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, "node_modules/karma/node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -8450,9 +8461,9 @@ } }, "node_modules/ng-primitives": { - "version": "0.74.0", - "resolved": "https://registry.npmjs.org/ng-primitives/-/ng-primitives-0.74.0.tgz", - "integrity": "sha512-Hw7qn7F8FriJCkO/QWTPWdvOKgsQABXfhiHqa/lt1vwgiDqoSrUVTdI0Jry9M3IuY8AoWJ/0wzq37HX98nQNWA==", + "version": "0.80.0", + "resolved": "https://registry.npmjs.org/ng-primitives/-/ng-primitives-0.80.0.tgz", + "integrity": "sha512-G8tlaVpn1Clq2dcM+CCDQ6cr5r9bJTXKoPSuR3eTJ1SjOPICJxGAakkhthtcAJAU9doebUFiUYIgI1352gK9Mg==", "license": "Apache-2.0", "dependencies": { "@phenomnomnominal/tsquery": "6.1.3", @@ -8870,16 +8881,6 @@ "license": "MIT", "optional": true }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/p-map": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", @@ -10460,16 +10461,13 @@ } }, "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "dev": true, "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, "engines": { - "node": ">=0.6.0" + "node": ">=14.14" } }, "node_modules/to-regex-range": { diff --git a/package.json b/package.json index ed3b4fc..71e950b 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@slateui/theme": "^1.0.0", "@tailwindcss/postcss": "^4.1.11", "express": "^5.1.0", - "ng-primitives": "^0.74.0", + "ng-primitives": "^0.80.0", "ngx-highlightjs": "^14.0.1", "postcss": "^8.5.6", "rxjs": "~7.8.0", diff --git a/projects/ui/src/directives/alert-dialog.ts b/projects/ui/src/directives/alert-dialog.ts index 8ce015a..ff18110 100644 --- a/projects/ui/src/directives/alert-dialog.ts +++ b/projects/ui/src/directives/alert-dialog.ts @@ -1,6 +1,6 @@ import { computed, Directive, input } from "@angular/core"; import { tv } from "tailwind-variants"; -import { NgpDialog, NgpDialogDescription, NgpDialogOverlay, NgpDialogTitle, NgpDialogTrigger } from "ng-primitives/dialog"; +import { NgpDialog, NgpDialogDescription, NgpDialogOverlay, NgpDialogTitle, NgpDialogTrigger, provideDialogConfig } from "ng-primitives/dialog"; const alertDialogVariants = tv({ slots: { @@ -105,7 +105,8 @@ export class UiAlertDialogFooter { 'ngpDialogTriggerCloseOnEscape: uiAlertDialogTriggerCloseOnEscape' ] } - ] + ], + providers: [provideDialogConfig({ closeOnEscape: false })] }) export class UiAlertDialogTrigger { inputClass = input('', { alias: 'class' }); @@ -125,7 +126,8 @@ export class UiAlertDialogTrigger { 'ngpDialogOverlayCloseOnClick: uiAlertDialogOverlayCloseOnClick' ] } - ] + ], + providers: [provideDialogConfig({ closeOnClick: false })] }) export class UiAlertDialogOverlay { inputClass = input('', { alias: 'class' }); From af2714ec341a474d1c9ce479b9646c6117e655e7 Mon Sep 17 00:00:00 2001 From: Mohammad Javed Date: Mon, 22 Sep 2025 16:05:08 +0530 Subject: [PATCH 3/8] UI(radio-group): Add radio group directive --- projects/ui/src/directives/radio-group.ts | 84 +++++++++++++++++++++++ projects/ui/src/public-api.ts | 3 +- 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 projects/ui/src/directives/radio-group.ts diff --git a/projects/ui/src/directives/radio-group.ts b/projects/ui/src/directives/radio-group.ts new file mode 100644 index 0000000..4203e5a --- /dev/null +++ b/projects/ui/src/directives/radio-group.ts @@ -0,0 +1,84 @@ +import { computed, Directive, input } from '@angular/core'; +import { tv } from "tailwind-variants"; +import { NgpRadioGroup, NgpRadioItem, NgpRadioIndicator } from 'ng-primitives/radio'; + +const radioGroupVariants = tv({ + slots: { + root: 'grid gap-3', + item: 'flex items-center space-x-2 cursor-pointer', + radio: 'relative border-input text-primary data-[focus-visible]:border-ring data-[focus-visible]:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none data-[focus-visible]:ring-[3px] data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50', + indicator: 'size-2 rounded-full absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2 data-[checked]:bg-primary' + } +}); + +const { root, item, radio, indicator } = radioGroupVariants(); + +@Directive({ + selector: '[uiRadioGroup]', + exportAs: 'uiRadioGroup', + host: { + '[class]': 'computedClass()' + }, + hostDirectives: [ + { + directive: NgpRadioGroup, + inputs: [ + 'ngpRadioGroupValue: defaultValue', + 'ngpRadioGroupDisabled: disabled' + ], + outputs: [ + 'ngpRadioGroupValueChange: defaultValueChange' + ], + }, + ], +}) +export class UiRadioGroup { + inputClass = input('', { alias: 'class' }); + computedClass = computed(() => root({ class: this.inputClass() })); +} + +@Directive({ + selector: '[uiRadioItem]', + exportAs: 'uiRadioItem', + host: { + '[class]': 'computedClass()' + }, + hostDirectives: [ + { + directive: NgpRadioItem, + inputs: [ + 'ngpRadioItemValue: value', + 'ngpRadioItemDisabled: disabled' + ], + }, + ], +}) +export class UiRadioItem { + inputClass = input('', { alias: 'class' }); + computedClass = computed(() => item({ class: this.inputClass() })); +} + +@Directive({ + selector: '[uiRadio]', + exportAs: 'uiRadio', + host: { + '[class]': 'computedClass()' + }, + hostDirectives: [NgpRadioIndicator] +}) +export class UiRadio { + inputClass = input('', { alias: 'class' }); + computedClass = computed(() => radio({ class: this.inputClass() })); +} + +@Directive({ + selector: '[uiRadioIndicator]', + exportAs: 'uiRadioIndicator', + host: { + '[class]': 'computedClass()' + } +}) +export class UiRadioIndicator { + inputClass = input('', { alias: 'class' }); + computedClass = computed(() => indicator({ class: this.inputClass() })); +} diff --git a/projects/ui/src/public-api.ts b/projects/ui/src/public-api.ts index eb1c919..469211c 100644 --- a/projects/ui/src/public-api.ts +++ b/projects/ui/src/public-api.ts @@ -23,4 +23,5 @@ export * from './directives/checkbox'; export * from './directives/toggle'; export * from './directives/toggle-group'; export * from './directives/skeleton'; -export * from './directives/switch'; \ No newline at end of file +export * from './directives/switch'; +export * from './directives/radio-group'; \ No newline at end of file From 0810b20f4f996ef6807c4fb4a3434daf9956de5a Mon Sep 17 00:00:00 2001 From: Mohammad Javed Date: Mon, 22 Sep 2025 16:05:31 +0530 Subject: [PATCH 4/8] docs(radio-group): Add radio group docs --- .../docs/components/components.routes.ts | 4 + .../components/radio-group/radio-group.ts | 19 + .../radio-group/radio-group.variants.ts | 344 ++++++++++++++++++ .../app/shared/components/sidebar/sidebar.ts | 1 + 4 files changed, 368 insertions(+) create mode 100644 projects/docs/src/app/pages/docs/components/radio-group/radio-group.ts create mode 100644 projects/docs/src/app/pages/docs/components/radio-group/radio-group.variants.ts diff --git a/projects/docs/src/app/pages/docs/components/components.routes.ts b/projects/docs/src/app/pages/docs/components/components.routes.ts index 4700696..bbd99c0 100644 --- a/projects/docs/src/app/pages/docs/components/components.routes.ts +++ b/projects/docs/src/app/pages/docs/components/components.routes.ts @@ -104,6 +104,10 @@ export const routes: Routes = [ path: 'switch', loadComponent: () => import('./switch/switch').then(m => m.Switch) }, + { + path: 'radio-group', + loadComponent: () => import('./radio-group/radio-group').then(m => m.RadioGroup) + }, { path: '', redirectTo: 'alert', diff --git a/projects/docs/src/app/pages/docs/components/radio-group/radio-group.ts b/projects/docs/src/app/pages/docs/components/radio-group/radio-group.ts new file mode 100644 index 0000000..b6cc8f7 --- /dev/null +++ b/projects/docs/src/app/pages/docs/components/radio-group/radio-group.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; +import { ComponentPreview } from '@components/component-preview/component-preview'; +import { radioGroupVariants, radioGroupMeta } from './radio-group.variants'; + +@Component({ + selector: 'docs-radio-group', + standalone: true, + imports: [ComponentPreview], + template: ` + + + ` +}) +export class RadioGroup { + radioGroupMeta = radioGroupMeta; + radioGroupVariants = radioGroupVariants; +} diff --git a/projects/docs/src/app/pages/docs/components/radio-group/radio-group.variants.ts b/projects/docs/src/app/pages/docs/components/radio-group/radio-group.variants.ts new file mode 100644 index 0000000..d85b371 --- /dev/null +++ b/projects/docs/src/app/pages/docs/components/radio-group/radio-group.variants.ts @@ -0,0 +1,344 @@ +import { Component, model } from '@angular/core'; +import { UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel } from 'ui'; +import { IVariant, IComponentMeta } from '@components/component-preview/component-preview'; + +// Radio Group example components for dynamic rendering +@Component({ + selector: 'radio-group-default-example', + template: ` +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ `, + imports: [UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel] +}) +export class RadioGroupDefaultExample { + selectedValue = model('comfortable'); +} + +@Component({ + selector: 'radio-group-disabled-example', + template: ` +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ `, + imports: [UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel] +}) +export class RadioGroupDisabledExample { + selectedValue = model('option1'); +} + +@Component({ + selector: 'radio-group-horizontal-example', + template: ` +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ `, + imports: [UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel] +}) +export class RadioGroupHorizontalExample { + selectedValue = model('yes'); +} + +@Component({ + selector: 'radio-group-form-example', + template: ` +
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+ `, + imports: [UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel] +}) +export class RadioGroupFormExample { + notificationType = model('all'); + + onSubmit() { + console.log('Selected:', this.notificationType()); + } +} + +export const radioGroupMeta: IComponentMeta = { + title: 'Radio Group', + description: 'A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.', + installation: { + package: 'radio-group', + import: `import { UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel } from '@workspace/ui/directives/radio-group';`, + usage: `
+
+
+
+
+ +
+
+
+
+
+ +
+
` + }, + api: { + props: [ + { + name: 'defaultValue', + type: 'string', + default: 'undefined', + description: 'The value of the selected radio button.' + }, + { + name: 'disabled', + type: 'boolean', + default: 'false', + description: 'Whether the radio group is disabled.' + }, + { + name: 'orientation', + type: '"vertical" | "horizontal"', + default: '"vertical"', + description: 'The orientation of the radio group.' + }, + { + name: 'class', + type: 'string', + description: 'Additional CSS classes to apply to the radio group.' + } + ], + outputs: [ + { + name: 'defaultValueChange', + type: 'string', + description: 'Emitted when the selected value changes.' + } + ] + } +}; + +export const radioGroupVariants: IVariant[] = [ + { + title: 'Default', + description: 'A basic radio group with multiple options.', + code: `import { Component, model } from '@angular/core'; +import { UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel } from '@workspace/ui/directives/radio-group'; + +@Component({ + selector: 'radio-group-default-example', + template: \` +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ \`, + imports: [UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel] +}) +export class RadioGroupDefaultExample { + selectedValue = model('comfortable'); +}`, + component: RadioGroupDefaultExample + }, + { + title: 'Disabled', + description: 'A disabled radio group where all options are non-interactive.', + code: `import { Component, model } from '@angular/core'; +import { UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel } from '@workspace/ui/directives/radio-group'; + +@Component({ + selector: 'radio-group-disabled-example', + template: \` +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ \`, + imports: [UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel] +}) +export class RadioGroupDisabledExample { + selectedValue = model('option1'); +}`, + component: RadioGroupDisabledExample + }, + { + title: 'Horizontal', + description: 'A radio group with horizontal orientation.', + code: `import { Component, model } from '@angular/core'; +import { UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel } from '@workspace/ui/directives/radio-group'; + +@Component({ + selector: 'radio-group-horizontal-example', + template: \` +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ \`, + imports: [UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel] +}) +export class RadioGroupHorizontalExample { + selectedValue = model('yes'); +}`, + component: RadioGroupHorizontalExample + }, + { + title: 'Form', + description: 'A radio group used in a form context with proper form integration.', + code: `import { Component, model } from '@angular/core'; +import { UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel } from '@workspace/ui/directives/radio-group'; + +@Component({ + selector: 'radio-group-form-example', + template: \` +
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+ \`, + imports: [UiRadioGroup, UiRadioItem, UiRadio, UiRadioIndicator, UiLabel] +}) +export class RadioGroupFormExample { + notificationType = model('all'); + + onSubmit() { + console.log('Selected:', this.notificationType()); + } +}`, + component: RadioGroupFormExample + } +]; diff --git a/projects/docs/src/app/shared/components/sidebar/sidebar.ts b/projects/docs/src/app/shared/components/sidebar/sidebar.ts index 6357783..0db45c9 100644 --- a/projects/docs/src/app/shared/components/sidebar/sidebar.ts +++ b/projects/docs/src/app/shared/components/sidebar/sidebar.ts @@ -67,6 +67,7 @@ export class Sidebar { { name: 'Popover', path: 'popover' }, { name: 'Progress', path: 'progress' }, // { name: 'Select', path: 'select' }, + { name: 'Radio Group', path: 'radio-group' }, { name: 'Separator', path: 'separator' }, { name: 'Switch', path: 'switch' }, { name: 'Tabs', path: 'tabs' }, From c75ce82fb468cfd6f62ff59b845039072ae7b15d Mon Sep 17 00:00:00 2001 From: Mohammad Javed Date: Wed, 24 Sep 2025 16:10:49 +0530 Subject: [PATCH 5/8] UI(alert): Migrate alert directives to components --- .../docs/components/alert/alert.variants.ts | 76 +++++++++---------- projects/ui/src/directives/alert.ts | 26 ++++--- 2 files changed, 54 insertions(+), 48 deletions(-) diff --git a/projects/docs/src/app/pages/docs/components/alert/alert.variants.ts b/projects/docs/src/app/pages/docs/components/alert/alert.variants.ts index fd62b22..d81fc0c 100644 --- a/projects/docs/src/app/pages/docs/components/alert/alert.variants.ts +++ b/projects/docs/src/app/pages/docs/components/alert/alert.variants.ts @@ -8,12 +8,12 @@ import { lucideCircleAlert } from '@ng-icons/lucide'; @Component({ selector: 'alert-default-example', template: ` -
-
Heads up!
-
+ + Heads up! + You can add components to your app using the CLI. -
-
+ + `, imports: [UiAlert, UiAlertTitle, UiAlertDescription] }) @@ -22,12 +22,12 @@ export class AlertDefaultExample {} @Component({ selector: 'alert-destructive-example', template: ` -
-
Error
-
+ + Error + Your session has expired. Please log in again. -
-
+ + `, imports: [UiAlert, UiAlertTitle, UiAlertDescription] }) @@ -36,13 +36,13 @@ export class AlertDestructiveExample {} @Component({ selector: 'alert-with-icon-example', template: ` -
+ -
Well done!
-
+ Well done! + You successfully read this important alert message. -
-
+ + `, providers: [provideIcons({ lucideCircleAlert })], imports: [UiAlert, UiAlertTitle, UiAlertDescription, NgIcon] @@ -54,11 +54,11 @@ export const alertMeta: IComponentMeta = { description: 'Displays a callout for user attention.', installation: { package: 'alert', - import: `import { UiAlert, UiAlertTitle, UiAlertDescription } from '@workspace/ui/directives/alert';`, - usage: `
-
Alert Title
-
Alert description
-
` + import: `import { UiAlert, UiAlertTitle, UiAlertDescription } from '@workspace/ui/alert';`, + usage: ` + Alert Title + Alert description +` }, api: { props: [ @@ -81,17 +81,17 @@ export const alertVariants: IVariant[] = [ { title: 'Default', description: 'The default alert appearance.', - code: `import { UiAlert, UiAlertTitle, UiAlertDescription } from '@workspace/ui/directives/alert'; + code: `import { UiAlert, UiAlertTitle, UiAlertDescription } from '@workspace/ui/alert'; @Component({ selector: 'alert-default-example', template: \` -
-
Heads up!
-
+ + Heads up! + You can add components to your app using the CLI. -
-
+ + \`, imports: [UiAlert, UiAlertTitle, UiAlertDescription] }) @@ -101,17 +101,17 @@ export class AlertDefaultExample {}`, { title: 'Destructive', description: 'An alert for error messages.', - code: `import { UiAlert, UiAlertTitle, UiAlertDescription } from '@workspace/ui/directives/alert'; + code: `import { UiAlert, UiAlertTitle, UiAlertDescription } from '@workspace/ui/alert'; @Component({ selector: 'alert-destructive-example', template: \` -
-
Error
-
+ + Error + Your session has expired. Please log in again. -
-
+ + \`, imports: [UiAlert, UiAlertTitle, UiAlertDescription] }) @@ -121,20 +121,20 @@ export class AlertDestructiveExample {}`, { title: 'With Icon', description: 'An alert with an icon.', - code: `import { UiAlert, UiAlertTitle, UiAlertDescription } from '@workspace/ui/directives/alert'; + code: `import { UiAlert, UiAlertTitle, UiAlertDescription } from '@workspace/ui/alert'; import { NgIcon, provideIcons } from '@ng-icons/core'; import { lucideCircleAlert } from '@ng-icons/lucide'; @Component({ selector: 'alert-with-icon-example', template: \` -
+ -
Well done!
-
+ Well done! + You successfully read this important alert message. -
-
+ + \`, providers: [provideIcons({ lucideCircleAlert })], imports: [UiAlert, UiAlertTitle, UiAlertDescription, NgIcon] diff --git a/projects/ui/src/directives/alert.ts b/projects/ui/src/directives/alert.ts index 447b5b9..26c3083 100644 --- a/projects/ui/src/directives/alert.ts +++ b/projects/ui/src/directives/alert.ts @@ -1,4 +1,4 @@ -import { computed, Directive, input } from '@angular/core'; +import { computed, Component, ChangeDetectionStrategy, input } from '@angular/core'; import { tv, VariantProps } from 'tailwind-variants'; const alertVariants = tv({ @@ -22,12 +22,14 @@ const { alert, alertTitle, alertDescription } = alertVariants(); type AlertVariants = VariantProps; -@Directive({ - selector: '[uiAlert]', +@Component({ + selector: 'ui-alert', exportAs: 'uiAlert', + changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'computedClass()' - } + }, + template: '' }) export class UiAlert { inputClass = input('', { alias: 'class' }); @@ -35,24 +37,28 @@ export class UiAlert { computedClass = computed(() => alert({ variant: this.variant(), class: this.inputClass() })); } -@Directive({ - selector: '[uiAlertTitle]', +@Component({ + selector: 'ui-alert-title', exportAs: 'uiAlertTitle', + changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'computedClass()' - } + }, + template: '' }) export class UiAlertTitle { inputClass = input('', { alias: 'class' }); computedClass = computed(() => alertTitle({ class: this.inputClass() })); } -@Directive({ - selector: '[uiAlertDescription]', +@Component({ + selector: 'ui-alert-description', exportAs: 'uiAlertDescription', + changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'computedClass()' - } + }, + template: '' }) export class UiAlertDescription { inputClass = input('', { alias: 'class' }); From 4cbf1bc5b131ba925cbd5b46b17a1a8478b46c76 Mon Sep 17 00:00:00 2001 From: Mohammad Javed Date: Sat, 4 Oct 2025 15:28:15 +0530 Subject: [PATCH 6/8] docs(header): Update header icons --- package-lock.json | 10 ++++++++++ package.json | 1 + .../src/app/pages/docs/introduction/introduction.html | 2 +- .../docs/src/app/shared/components/header/header.html | 4 ++-- .../docs/src/app/shared/components/header/header.ts | 6 ++---- projects/docs/src/index.html | 4 ++-- 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 57fe32c..5529199 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@ng-icons/bootstrap-icons": "^32.1.0", "@ng-icons/core": "^32.1.0", "@ng-icons/lucide": "^32.1.0", + "@ng-icons/tabler-icons": "^32.1.0", "@slateui/theme": "^1.0.0", "@tailwindcss/postcss": "^4.1.11", "express": "^5.1.0", @@ -2644,6 +2645,15 @@ "tslib": "^2.3.0" } }, + "node_modules/@ng-icons/tabler-icons": { + "version": "32.1.0", + "resolved": "https://registry.npmjs.org/@ng-icons/tabler-icons/-/tabler-icons-32.1.0.tgz", + "integrity": "sha512-zqUaJcpllT7kl2UYExoO6oTnLtaQweSKs2wBK4xRsPlhwaU8RjbmZFdYLfa/IAEvLveD5D1i0orIPepu55ESqQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + } + }, "node_modules/@npmcli/agent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", diff --git a/package.json b/package.json index 71e950b..eab97aa 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "@ng-icons/bootstrap-icons": "^32.1.0", "@ng-icons/core": "^32.1.0", "@ng-icons/lucide": "^32.1.0", + "@ng-icons/tabler-icons": "^32.1.0", "@slateui/theme": "^1.0.0", "@tailwindcss/postcss": "^4.1.11", "express": "^5.1.0", diff --git a/projects/docs/src/app/pages/docs/introduction/introduction.html b/projects/docs/src/app/pages/docs/introduction/introduction.html index f6c64e4..4505c0f 100644 --- a/projects/docs/src/app/pages/docs/introduction/introduction.html +++ b/projects/docs/src/app/pages/docs/introduction/introduction.html @@ -104,7 +104,7 @@

Responsive

-
+