@spartan-ng/cli 0.0.1-alpha.502 → 0.0.1-alpha.503

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/package.json +1 -1
  2. package/src/generators/healthcheck/generator.js +2 -0
  3. package/src/generators/healthcheck/generator.js.map +1 -1
  4. package/src/generators/healthcheck/healthchecks/hlm-date-picker.d.ts +2 -0
  5. package/src/generators/healthcheck/healthchecks/hlm-date-picker.js +32 -0
  6. package/src/generators/healthcheck/healthchecks/hlm-date-picker.js.map +1 -0
  7. package/src/generators/migrate-date-picker/compat.d.ts +2 -0
  8. package/src/generators/migrate-date-picker/compat.js +7 -0
  9. package/src/generators/migrate-date-picker/compat.js.map +1 -0
  10. package/src/generators/migrate-date-picker/generator.d.ts +4 -0
  11. package/src/generators/migrate-date-picker/generator.js +29 -0
  12. package/src/generators/migrate-date-picker/generator.js.map +1 -0
  13. package/src/generators/migrate-date-picker/schema.d.ts +3 -0
  14. package/src/generators/migrate-date-picker/schema.json +14 -0
  15. package/src/generators/ui/libs/ui-button-helm/files/lib/hlm-button.ts.template +4 -2
  16. package/src/generators/ui/libs/ui-calendar-helm/files/index.ts.template +3 -1
  17. package/src/generators/ui/libs/ui-calendar-helm/files/lib/hlm-calendar-range.ts.template +183 -0
  18. package/src/generators/ui/libs/ui-date-picker-helm/files/index.ts.template +4 -1
  19. package/src/generators/ui/libs/ui-date-picker-helm/files/lib/hlm-date-picker-multi.ts.template +26 -29
  20. package/src/generators/ui/libs/ui-date-picker-helm/files/lib/hlm-date-picker.ts.template +24 -27
  21. package/src/generators/ui/libs/ui-date-picker-helm/files/lib/hlm-date-range-picker.token.ts.template +47 -0
  22. package/src/generators/ui/libs/ui-date-picker-helm/files/lib/hlm-date-range-picker.ts.template +194 -0
  23. package/src/generators/ui/libs/ui-switch-helm/files/lib/hlm-switch.ts.template +5 -8
  24. package/src/generators/ui/supported-ui-libraries.json +40 -40
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spartan-ng/cli",
3
- "version": "0.0.1-alpha.502",
3
+ "version": "0.0.1-alpha.503",
4
4
  "type": "commonjs",
5
5
  "dependencies": {
6
6
  "@nx/angular": ">=20.0.0",
@@ -8,6 +8,7 @@ const brn_radio_1 = require("./healthchecks/brn-radio");
8
8
  const brn_toggle_group_1 = require("./healthchecks/brn-toggle-group");
9
9
  const core_imports_1 = require("./healthchecks/core-imports");
10
10
  const helm_imports_1 = require("./healthchecks/helm-imports");
11
+ const hlm_date_picker_1 = require("./healthchecks/hlm-date-picker");
11
12
  const hlm_icon_1 = require("./healthchecks/hlm-icon");
12
13
  const hlm_progress_1 = require("./healthchecks/hlm-progress");
13
14
  const hlm_scroll_area_1 = require("./healthchecks/hlm-scroll-area");
@@ -30,6 +31,7 @@ async function healthcheckGenerator(tree, options) {
30
31
  brn_toggle_group_1.brainToggleHealthcheck,
31
32
  helm_imports_1.helmImportsHealthcheck,
32
33
  naming_conventions_1.namingConventionHealthcheck,
34
+ hlm_date_picker_1.datePickerHealthcheck,
33
35
  hlm_progress_1.progressHealthcheck,
34
36
  ];
35
37
  const failedReports = [];
@@ -1 +1 @@
1
- {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/generators/healthcheck/generator.ts"],"names":[],"mappings":";;AAkBA,oDAyCC;AA3DD,uCAAuD;AACvD,iDAAyG;AACzG,gEAAuE;AACvE,wDAAiE;AACjE,sEAAyE;AACzE,8DAAqE;AACrE,8DAAqE;AACrE,sDAA8D;AAC9D,8DAAkE;AAClE,oEAAuE;AACvE,0DAA8D;AAC9D,0EAAgF;AAChF,oDAA4D;AAE5D,2CAA4C;AAC5C,+CAA+C;AAC/C,2CAAgD;AAEzC,KAAK,UAAU,oBAAoB,CAAC,IAAU,EAAE,OAA8D;IACpH,eAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAEvC,MAAM,YAAY,GAAkB;QACnC,4BAAkB;QAClB,uCAAuB;QACvB,qCAAsB;QACtB,8BAAmB;QACnB,uCAAqB;QACrB,iCAAqB;QACrB,8BAAiB;QACjB,yCAAsB;QACtB,qCAAsB;QACtB,gDAA2B;QAC3B,kCAAmB;KACnB,CAAC;IAEF,MAAM,aAAa,GAAwB,EAAE,CAAC;IAE9C,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,IAAA,uBAAc,EAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACvD,IAAA,sBAAW,EAAC,MAAM,CAAC,CAAC;QAEpB,IAAI,MAAM,CAAC,MAAM,KAAK,gCAAiB,CAAC,OAAO,EAAE,CAAC;YACjD,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;IACF,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;QACpC,IAAI,MAAM,CAAC,OAAO,IAAI,IAAA,mCAAoB,EAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;YAChE,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,MAAM,IAAA,mBAAU,EAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;YAE7E,IAAI,GAAG,EAAE,CAAC;gBACT,MAAM,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;YACxE,CAAC;QACF,CAAC;IACF,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACzB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IACzB,CAAC;AACF,CAAC;AAED,kBAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/generators/healthcheck/generator.ts"],"names":[],"mappings":";;AAmBA,oDA0CC;AA7DD,uCAAuD;AACvD,iDAAyG;AACzG,gEAAuE;AACvE,wDAAiE;AACjE,sEAAyE;AACzE,8DAAqE;AACrE,8DAAqE;AACrE,oEAAuE;AACvE,sDAA8D;AAC9D,8DAAkE;AAClE,oEAAuE;AACvE,0DAA8D;AAC9D,0EAAgF;AAChF,oDAA4D;AAE5D,2CAA4C;AAC5C,+CAA+C;AAC/C,2CAAgD;AAEzC,KAAK,UAAU,oBAAoB,CAAC,IAAU,EAAE,OAA8D;IACpH,eAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAEvC,MAAM,YAAY,GAAkB;QACnC,4BAAkB;QAClB,uCAAuB;QACvB,qCAAsB;QACtB,8BAAmB;QACnB,uCAAqB;QACrB,iCAAqB;QACrB,8BAAiB;QACjB,yCAAsB;QACtB,qCAAsB;QACtB,gDAA2B;QAC3B,uCAAqB;QACrB,kCAAmB;KACnB,CAAC;IAEF,MAAM,aAAa,GAAwB,EAAE,CAAC;IAE9C,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,IAAA,uBAAc,EAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACvD,IAAA,sBAAW,EAAC,MAAM,CAAC,CAAC;QAEpB,IAAI,MAAM,CAAC,MAAM,KAAK,gCAAiB,CAAC,OAAO,EAAE,CAAC;YACjD,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;IACF,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;QACpC,IAAI,MAAM,CAAC,OAAO,IAAI,IAAA,mCAAoB,EAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;YAChE,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,MAAM,IAAA,mBAAU,EAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;YAE7E,IAAI,GAAG,EAAE,CAAC;gBACT,MAAM,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;YACxE,CAAC;QACF,CAAC;IACF,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACzB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IACzB,CAAC;AACF,CAAC;AAED,kBAAe,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Healthcheck } from '../healthchecks';
2
+ export declare const datePickerHealthcheck: Healthcheck;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.datePickerHealthcheck = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const devkit_1 = require("@nx/devkit");
6
+ const generator_1 = tslib_1.__importDefault(require("../../migrate-date-picker/generator"));
7
+ const healthchecks_1 = require("../healthchecks");
8
+ exports.datePickerHealthcheck = {
9
+ name: 'Helm DatePicker',
10
+ async detect(tree, failure) {
11
+ (0, devkit_1.visitNotIgnoredFiles)(tree, '/', (file) => {
12
+ // if the file is a .ts or .htlm file, check for helm icons
13
+ if (!file.endsWith('.ts') && !file.endsWith('.html')) {
14
+ return;
15
+ }
16
+ const contents = tree.read(file, 'utf-8');
17
+ if (!contents) {
18
+ return;
19
+ }
20
+ // check if the legacy openedChange event is being used
21
+ if (/<(hlm-date-picker)[^>]*\(\s*changed\s*\)=/g.test(contents)) {
22
+ failure('DatePicker is using the renamed changed event.', healthchecks_1.HealthcheckSeverity.Error, true);
23
+ }
24
+ });
25
+ },
26
+ fix: async (tree) => {
27
+ await (0, generator_1.default)(tree, { skipFormat: true });
28
+ return true;
29
+ },
30
+ prompt: 'Would you like to migrate date picker?',
31
+ };
32
+ //# sourceMappingURL=hlm-date-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hlm-date-picker.js","sourceRoot":"","sources":["../../../../../../../libs/cli/src/generators/healthcheck/healthchecks/hlm-date-picker.ts"],"names":[],"mappings":";;;;AAAA,uCAAkD;AAClD,4FAA6E;AAC7E,kDAAmE;AAEtD,QAAA,qBAAqB,GAAgB;IACjD,IAAI,EAAE,iBAAiB;IACvB,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO;QACzB,IAAA,6BAAoB,EAAC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;YACxC,2DAA2D;YAC3D,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBACtD,OAAO;YACR,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAE1C,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACf,OAAO;YACR,CAAC;YAED,uDAAuD;YACvD,IAAI,4CAA4C,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACjE,OAAO,CAAC,gDAAgD,EAAE,kCAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAC5F,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IACD,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACnB,MAAM,IAAA,mBAA0B,EAAC,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,EAAE,wCAAwC;CAChD,CAAC"}
@@ -0,0 +1,2 @@
1
+ declare const _default: (generatorOptions: import("./schema").MigrateDatePickerGeneratorSchema) => (tree: any, context: any) => Promise<any>;
2
+ export default _default;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const devkit_1 = require("@nx/devkit");
5
+ const generator_1 = tslib_1.__importDefault(require("./generator"));
6
+ exports.default = (0, devkit_1.convertNxGenerator)(generator_1.default);
7
+ //# sourceMappingURL=compat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compat.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/generators/migrate-date-picker/compat.ts"],"names":[],"mappings":";;;AAAA,uCAAgD;AAChD,oEAAiD;AAEjD,kBAAe,IAAA,2BAAkB,EAAC,mBAAsB,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Tree } from '@nx/devkit';
2
+ import { MigrateDatePickerGeneratorSchema } from './schema';
3
+ export declare function migrateDatePickerGenerator(tree: Tree, { skipFormat }: MigrateDatePickerGeneratorSchema): Promise<void>;
4
+ export default migrateDatePickerGenerator;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.migrateDatePickerGenerator = migrateDatePickerGenerator;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const visit_files_1 = require("../../utils/visit-files");
6
+ async function migrateDatePickerGenerator(tree, { skipFormat }) {
7
+ replaceOpenChangeEvent(tree);
8
+ if (!skipFormat) {
9
+ await (0, devkit_1.formatFiles)(tree);
10
+ }
11
+ }
12
+ function replaceOpenChangeEvent(tree) {
13
+ // if the element is `'<hlm-select' and it has an `(openedChange)` event, we need to replace it with `(openChange)`
14
+ (0, visit_files_1.visitFiles)(tree, '.', (path) => {
15
+ // if this is not an html file or typescript file (inline templates) then skip
16
+ if (!path.endsWith('.html') && !path.endsWith('.ts')) {
17
+ return;
18
+ }
19
+ let content = tree.read(path, 'utf-8');
20
+ if (!content) {
21
+ return;
22
+ }
23
+ // find all the brn-select or hlm-select elements that have an `(openedChange)` event
24
+ content = content.replace(/<(hlm-date-picker)[^>]*\(\s*changed\s*\)=/g, (match) => match.replace(/\(\s*changed\s*\)/, '(dateChange)'));
25
+ tree.write(path, content);
26
+ });
27
+ }
28
+ exports.default = migrateDatePickerGenerator;
29
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/generators/migrate-date-picker/generator.ts"],"names":[],"mappings":";;AAIA,gEAMC;AAVD,uCAA+C;AAC/C,yDAAqD;AAG9C,KAAK,UAAU,0BAA0B,CAAC,IAAU,EAAE,EAAE,UAAU,EAAoC;IAC5G,sBAAsB,CAAC,IAAI,CAAC,CAAC;IAE7B,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IACzB,CAAC;AACF,CAAC;AAED,SAAS,sBAAsB,CAAC,IAAU;IACzC,mHAAmH;IACnH,IAAA,wBAAU,EAAC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;QAC9B,8EAA8E;QAC9E,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACtD,OAAO;QACR,CAAC;QAED,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAEvC,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,OAAO;QACR,CAAC;QAED,qFAAqF;QACrF,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,4CAA4C,EAAE,CAAC,KAAK,EAAE,EAAE,CACjF,KAAK,CAAC,OAAO,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAClD,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,kBAAe,0BAA0B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export interface MigrateDatePickerGeneratorSchema {
2
+ skipFormat?: boolean;
3
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema",
3
+ "$id": "MigrateSelect",
4
+ "title": "",
5
+ "type": "object",
6
+ "properties": {
7
+ "skipFormat": {
8
+ "type": "boolean",
9
+ "default": false,
10
+ "description": "Skip formatting files"
11
+ }
12
+ },
13
+ "required": []
14
+ }
@@ -1,11 +1,12 @@
1
1
  import { Directive, computed, input, signal } from '@angular/core';
2
+ import { BrnButton } from '@spartan-ng/brain/button';
2
3
  import { hlm } from '@spartan-ng/brain/core';
3
4
  import { type VariantProps, cva } from 'class-variance-authority';
4
5
  import type { ClassValue } from 'clsx';
5
6
  import { injectBrnButtonConfig } from './hlm-button.token';
6
7
 
7
8
  export const buttonVariants = cva(
8
- 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_ng-icon]:pointer-events-none shrink-0 [&_ng-icon]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive cursor-default',
9
+ 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_ng-icon]:pointer-events-none shrink-0 [&_ng-icon]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive cursor-default',
9
10
  {
10
11
  variants: {
11
12
  variant: {
@@ -35,8 +36,9 @@ export const buttonVariants = cva(
35
36
  export type ButtonVariants = VariantProps<typeof buttonVariants>;
36
37
 
37
38
  @Directive({
38
- selector: '[hlmBtn]',
39
+ selector: 'button[hlmBtn], a[hlmBtn]',
39
40
  exportAs: 'hlmBtn',
41
+ hostDirectives: [{ directive: BrnButton, inputs: ['disabled'] }],
40
42
  host: {
41
43
  '[class]': '_computedClass()',
42
44
  },
@@ -1,11 +1,13 @@
1
1
  import { NgModule } from '@angular/core';
2
2
  import { HlmCalendar } from './lib/hlm-calendar';
3
3
  import { HlmCalendarMulti } from './lib/hlm-calendar-multi';
4
+ import { HlmCalendarRange } from './lib/hlm-calendar-range';
4
5
 
5
6
  export * from './lib/hlm-calendar';
6
7
  export * from './lib/hlm-calendar-multi';
8
+ export * from './lib/hlm-calendar-range';
7
9
 
8
- export const HlmCalendarImports = [HlmCalendar, HlmCalendarMulti] as const;
10
+ export const HlmCalendarImports = [HlmCalendar, HlmCalendarMulti, HlmCalendarRange] as const;
9
11
 
10
12
  @NgModule({
11
13
  imports: [...HlmCalendarImports],
@@ -0,0 +1,183 @@
1
+ import { BooleanInput, NumberInput } from '@angular/cdk/coercion';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ booleanAttribute,
6
+ computed,
7
+ input,
8
+ model,
9
+ numberAttribute,
10
+ viewChild,
11
+ } from '@angular/core';
12
+ import { NgIcon, provideIcons } from '@ng-icons/core';
13
+ import { lucideChevronLeft, lucideChevronRight } from '@ng-icons/lucide';
14
+ import {
15
+ BrnCalendarCell,
16
+ BrnCalendarCellButton,
17
+ BrnCalendarGrid,
18
+ BrnCalendarHeader,
19
+ BrnCalendarNextButton,
20
+ BrnCalendarPreviousButton,
21
+ BrnCalendarRange,
22
+ BrnCalendarWeek,
23
+ BrnCalendarWeekday,
24
+ Weekday,
25
+ injectBrnCalendarI18n,
26
+ } from '@spartan-ng/brain/calendar';
27
+ import { hlm } from '@spartan-ng/brain/core';
28
+ import { injectDateAdapter } from '@spartan-ng/brain/date-time';
29
+ import { buttonVariants } from '@spartan-ng/helm/button';
30
+ import { HlmIcon } from '@spartan-ng/helm/icon';
31
+ import type { ClassValue } from 'clsx';
32
+
33
+ @Component({
34
+ selector: 'hlm-calendar-range',
35
+ imports: [
36
+ BrnCalendarHeader,
37
+ BrnCalendarNextButton,
38
+ BrnCalendarPreviousButton,
39
+ BrnCalendarWeekday,
40
+ BrnCalendarWeek,
41
+ BrnCalendarCellButton,
42
+ BrnCalendarCell,
43
+ BrnCalendarGrid,
44
+ NgIcon,
45
+ HlmIcon,
46
+ BrnCalendarRange,
47
+ ],
48
+ viewProviders: [provideIcons({ lucideChevronLeft, lucideChevronRight })],
49
+ template: `
50
+ <div
51
+ brnCalendarRange
52
+ [min]="min()"
53
+ [max]="max()"
54
+ [disabled]="disabled()"
55
+ [(startDate)]="startDate"
56
+ [(endDate)]="endDate"
57
+ [dateDisabled]="dateDisabled()"
58
+ [weekStartsOn]="weekStartsOn()"
59
+ [defaultFocusedDate]="defaultFocusedDate()"
60
+ [class]="_computedCalenderClass()"
61
+ >
62
+ <div class="inline-flex flex-col space-y-4">
63
+ <!-- Header -->
64
+ <div class="space-y-4">
65
+ <div class="relative flex items-center justify-center pt-1">
66
+ <div brnCalendarHeader class="text-sm font-medium">
67
+ {{ _heading() }}
68
+ </div>
69
+
70
+ <div class="flex items-center space-x-1">
71
+ <button
72
+ brnCalendarPreviousButton
73
+ class="ring-offset-background focus-visible:ring-ring border-input hover:bg-accent hover:text-accent-foreground absolute left-1 inline-flex h-7 w-7 items-center justify-center whitespace-nowrap rounded-md border bg-transparent p-0 text-sm font-medium opacity-50 transition-colors hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
74
+ >
75
+ <ng-icon hlm name="lucideChevronLeft" size="sm" />
76
+ </button>
77
+
78
+ <button
79
+ brnCalendarNextButton
80
+ class="ring-offset-background focus-visible:ring-ring border-input hover:bg-accent hover:text-accent-foreground absolute right-1 inline-flex h-7 w-7 items-center justify-center whitespace-nowrap rounded-md border bg-transparent p-0 text-sm font-medium opacity-50 transition-colors hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
81
+ >
82
+ <ng-icon hlm name="lucideChevronRight" size="sm" />
83
+ </button>
84
+ </div>
85
+ </div>
86
+ </div>
87
+
88
+ <table class="w-full border-collapse space-y-1" brnCalendarGrid>
89
+ <thead>
90
+ <tr class="flex">
91
+ <th
92
+ *brnCalendarWeekday="let weekday"
93
+ scope="col"
94
+ class="text-muted-foreground w-8 rounded-md text-[0.8rem] font-normal"
95
+ [attr.aria-label]="_i18n.labelWeekday(weekday)"
96
+ >
97
+ {{ _i18n.formatWeekdayName(weekday) }}
98
+ </th>
99
+ </tr>
100
+ </thead>
101
+
102
+ <tbody role="rowgroup">
103
+ <tr *brnCalendarWeek="let week" class="mt-2 flex w-full">
104
+ @for (date of week; track _dateAdapter.getTime(date)) {
105
+ <td
106
+ brnCalendarCell
107
+ class="data-[selected]:data-[outside]:bg-accent/50 data-[selected]:bg-accent relative h-8 w-8 p-0 text-center text-sm focus-within:relative focus-within:z-20 first:data-[selected]:rounded-l-md last:data-[selected]:rounded-r-md [&:has([aria-selected].day-range-end)]:rounded-r-md"
108
+ >
109
+ <button brnCalendarCellButton [date]="date" [class]="_btnClass">
110
+ {{ _dateAdapter.getDate(date) }}
111
+ </button>
112
+ </td>
113
+ }
114
+ </tr>
115
+ </tbody>
116
+ </table>
117
+ </div>
118
+ </div>
119
+ `,
120
+ changeDetection: ChangeDetectionStrategy.OnPush,
121
+ })
122
+ export class HlmCalendarRange<T> {
123
+ public readonly calendarClass = input<ClassValue>('');
124
+
125
+ protected readonly _computedCalenderClass = computed(() => hlm('rounded-md border p-3', this.calendarClass()));
126
+
127
+ /** Access the calendar i18n */
128
+ protected readonly _i18n = injectBrnCalendarI18n();
129
+
130
+ /** Access the date time adapter */
131
+ protected readonly _dateAdapter = injectDateAdapter<T>();
132
+
133
+ /** The minimum date that can be selected.*/
134
+ public readonly min = input<T>();
135
+
136
+ /** The maximum date that can be selected. */
137
+ public readonly max = input<T>();
138
+
139
+ /** Determine if the date picker is disabled. */
140
+ public readonly disabled = input<boolean, BooleanInput>(false, {
141
+ transform: booleanAttribute,
142
+ });
143
+
144
+ /** The start date of the range. */
145
+ public readonly startDate = model<T>();
146
+
147
+ /** The end date of the range. */
148
+ public readonly endDate = model<T>();
149
+
150
+ /** Whether a specific date is disabled. */
151
+ public readonly dateDisabled = input<(date: T) => boolean>(() => false);
152
+
153
+ /** The day the week starts on */
154
+ public readonly weekStartsOn = input<Weekday, NumberInput>(0, {
155
+ transform: (v: unknown) => numberAttribute(v) as Weekday,
156
+ });
157
+
158
+ /** The default focused date. */
159
+ public readonly defaultFocusedDate = input<T>();
160
+
161
+ /** Access the calendar directive */
162
+ private readonly _calendar = viewChild.required(BrnCalendarRange);
163
+
164
+ /** Get the heading for the current month and year */
165
+ protected readonly _heading = computed(() =>
166
+ this._i18n.formatHeader(
167
+ this._dateAdapter.getMonth(this._calendar().focusedDate()),
168
+ this._dateAdapter.getYear(this._calendar().focusedDate()),
169
+ ),
170
+ );
171
+
172
+ protected readonly _btnClass = hlm(
173
+ buttonVariants({ variant: 'ghost' }),
174
+ 'size-8 p-0 font-normal aria-selected:opacity-100',
175
+ 'data-[outside]:text-muted-foreground data-[outside]:aria-selected:text-muted-foreground',
176
+ 'data-[today]:bg-accent data-[today]:text-accent-foreground',
177
+ 'data-[selected]:bg-primary data-[selected]:text-primary-foreground data-[selected]:focus:bg-primary data-[selected]:focus:text-primary-foreground',
178
+ 'data-[disabled]:text-muted-foreground data-[disabled]:opacity-50',
179
+ 'data-[range-start]:rounded-l-md',
180
+ 'data-[range-end]:rounded-r-md',
181
+ 'data-[range-between]:rounded-none data-[range-between]:bg-accent data-[range-between]:text-accent-foreground',
182
+ );
183
+ }
@@ -1,13 +1,16 @@
1
1
  import { NgModule } from '@angular/core';
2
2
  import { HlmDatePicker } from './lib/hlm-date-picker';
3
3
  import { HlmDatePickerMulti } from './lib/hlm-date-picker-multi';
4
+ import { HlmDateRangePicker } from './lib/hlm-date-range-picker';
4
5
 
5
6
  export * from './lib/hlm-date-picker.token';
6
7
 
7
8
  export * from './lib/hlm-date-picker';
8
9
  export * from './lib/hlm-date-picker-multi';
10
+ export * from './lib/hlm-date-range-picker';
11
+ export * from './lib/hlm-date-range-picker.token';
9
12
 
10
- export const HlmDatePickerImports = [HlmDatePicker, HlmDatePickerMulti] as const;
13
+ export const HlmDatePickerImports = [HlmDatePicker, HlmDatePickerMulti, HlmDateRangePicker] as const;
11
14
 
12
15
  @NgModule({
13
16
  imports: [...HlmDatePickerImports],
@@ -6,7 +6,7 @@ import {
6
6
  computed,
7
7
  forwardRef,
8
8
  input,
9
- model,
9
+ linkedSignal,
10
10
  numberAttribute,
11
11
  output,
12
12
  signal,
@@ -36,7 +36,7 @@ export const HLM_DATE_PICKER_MUTLI_VALUE_ACCESSOR = {
36
36
  providers: [HLM_DATE_PICKER_MUTLI_VALUE_ACCESSOR, provideIcons({ lucideCalendar })],
37
37
  template: `
38
38
  <brn-popover sideOffset="5" [state]="_popoverState()" (stateChanged)="_popoverState.set($event)">
39
- <button type="button" [class]="_computedClass()" [disabled]="_state().disabled()" brnPopoverTrigger>
39
+ <button type="button" [class]="_computedClass()" [disabled]="_mutableDisabled()" brnPopoverTrigger>
40
40
  <ng-icon hlm size="sm" name="lucideCalendar" />
41
41
 
42
42
  <span class="truncate">
@@ -51,12 +51,12 @@ export const HLM_DATE_PICKER_MUTLI_VALUE_ACCESSOR = {
51
51
  <div hlmPopoverContent class="w-auto p-0" *brnPopoverContent="let ctx">
52
52
  <hlm-calendar-multi
53
53
  calendarClass="border-0 rounded-none"
54
- [date]="date()"
54
+ [date]="_mutableDate()"
55
55
  [min]="min()"
56
56
  [max]="max()"
57
57
  [minSelection]="minSelection()"
58
58
  [maxSelection]="maxSelection()"
59
- [disabled]="_state().disabled()"
59
+ [disabled]="_mutableDisabled()"
60
60
  (dateChange)="_handleChange($event)"
61
61
  />
62
62
  </div>
@@ -73,11 +73,11 @@ export class HlmDatePickerMulti<T> implements ControlValueAccessor {
73
73
  public readonly userClass = input<ClassValue>('', { alias: 'class' });
74
74
  protected readonly _computedClass = computed(() =>
75
75
  hlm(
76
- 'inline-flex items-center gap-2 whitespace-nowrap rounded-md text-sm ring-offset-background transition-colors border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2 w-[280px] justify-start text-left font-normal',
76
+ 'inline-flex items-center gap-2 whitespace-nowrap rounded-md text-sm ring-offset-background transition-all border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2 w-[280px] justify-start text-left font-normal',
77
77
  'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
78
78
  'disabled:pointer-events-none disabled:opacity-50',
79
79
  '[&_ng-icon]:pointer-events-none [&_ng-icon]:shrink-0',
80
- !this.date() ? 'text-muted-foreground' : '',
80
+ !this._mutableDate() ? 'text-muted-foreground' : '',
81
81
  this.userClass(),
82
82
  ),
83
83
  );
@@ -104,9 +104,11 @@ export class HlmDatePickerMulti<T> implements ControlValueAccessor {
104
104
  });
105
105
 
106
106
  /** The selected value. */
107
- public readonly date = model<T[]>();
107
+ public readonly date = input<T[]>();
108
108
 
109
- /** If true, the date picker will close when the max selection of dates is reached.. */
109
+ protected readonly _mutableDate = linkedSignal(this.date);
110
+
111
+ /** If true, the date picker will close when the max selection of dates is reached. */
110
112
  public readonly autoCloseOnMaxSelection = input<boolean, BooleanInput>(this._config.autoCloseOnMaxSelection, {
111
113
  transform: booleanAttribute,
112
114
  });
@@ -119,16 +121,14 @@ export class HlmDatePickerMulti<T> implements ControlValueAccessor {
119
121
 
120
122
  protected readonly _popoverState = signal<BrnDialogState | null>(null);
121
123
 
122
- protected readonly _state = computed(() => ({
123
- disabled: signal(this.disabled()),
124
- }));
124
+ protected readonly _mutableDisabled = linkedSignal(this.disabled);
125
125
 
126
126
  protected readonly _formattedDate = computed(() => {
127
- const dates = this.date();
127
+ const dates = this._mutableDate();
128
128
  return dates ? this.formatDates()(dates) : undefined;
129
129
  });
130
130
 
131
- public readonly changed = output<T[]>();
131
+ public readonly dateChange = output<T[]>();
132
132
 
133
133
  protected _onChange?: ChangeFn<T[]>;
134
134
  protected _onTouched?: TouchFn;
@@ -136,43 +136,40 @@ export class HlmDatePickerMulti<T> implements ControlValueAccessor {
136
136
  protected _handleChange(value: T[] | undefined) {
137
137
  if (value === undefined) return;
138
138
 
139
- if (this._state().disabled()) return;
139
+ if (this._mutableDisabled()) return;
140
140
  const transformedDate = this.transformDates()(value);
141
141
 
142
- this.date.set(transformedDate);
142
+ this._mutableDate.set(transformedDate);
143
143
  this._onChange?.(transformedDate);
144
- this.changed.emit(transformedDate);
144
+ this.dateChange.emit(transformedDate);
145
145
 
146
- if (this.autoCloseOnMaxSelection() && this.date()?.length === this.maxSelection()) {
146
+ if (this.autoCloseOnMaxSelection() && this._mutableDate()?.length === this.maxSelection()) {
147
147
  this._popoverState.set('closed');
148
148
  }
149
149
  }
150
150
 
151
- /** CONROL VALUE ACCESSOR */
152
- writeValue(value: T[] | null): void {
153
- // optional FormControl is initialized with null value
154
- if (value === null) return;
155
-
156
- this.date.set(this.transformDates()(value));
151
+ /** CONTROL VALUE ACCESSOR */
152
+ public writeValue(value: T[] | null): void {
153
+ this._mutableDate.set(value ? this.transformDates()(value) : undefined);
157
154
  }
158
155
 
159
- registerOnChange(fn: ChangeFn<T[]>): void {
156
+ public registerOnChange(fn: ChangeFn<T[]>): void {
160
157
  this._onChange = fn;
161
158
  }
162
159
 
163
- registerOnTouched(fn: TouchFn): void {
160
+ public registerOnTouched(fn: TouchFn): void {
164
161
  this._onTouched = fn;
165
162
  }
166
163
 
167
- setDisabledState(isDisabled: boolean): void {
168
- this._state().disabled.set(isDisabled);
164
+ public setDisabledState(isDisabled: boolean): void {
165
+ this._mutableDisabled.set(isDisabled);
169
166
  }
170
167
 
171
- open() {
168
+ public open() {
172
169
  this._popoverState.set('open');
173
170
  }
174
171
 
175
- close() {
172
+ public close() {
176
173
  this._popoverState.set('closed');
177
174
  }
178
175
  }
@@ -6,7 +6,7 @@ import {
6
6
  computed,
7
7
  forwardRef,
8
8
  input,
9
- model,
9
+ linkedSignal,
10
10
  output,
11
11
  signal,
12
12
  } from '@angular/core';
@@ -35,7 +35,7 @@ export const HLM_DATE_PICKER_VALUE_ACCESSOR = {
35
35
  providers: [HLM_DATE_PICKER_VALUE_ACCESSOR, provideIcons({ lucideChevronDown })],
36
36
  template: `
37
37
  <brn-popover sideOffset="5" [state]="_popoverState()" (stateChanged)="_popoverState.set($event)">
38
- <button type="button" [class]="_computedClass()" [disabled]="_state().disabled()" brnPopoverTrigger>
38
+ <button type="button" [class]="_computedClass()" [disabled]="_mutableDisabled()" brnPopoverTrigger>
39
39
  <span class="truncate">
40
40
  @if (_formattedDate(); as formattedDate) {
41
41
  {{ formattedDate }}
@@ -50,10 +50,10 @@ export const HLM_DATE_PICKER_VALUE_ACCESSOR = {
50
50
  <div hlmPopoverContent class="w-auto p-0" *brnPopoverContent="let ctx">
51
51
  <hlm-calendar
52
52
  calendarClass="border-0 rounded-none"
53
- [date]="date()"
53
+ [date]="_mutableDate()"
54
54
  [min]="min()"
55
55
  [max]="max()"
56
- [disabled]="_state().disabled()"
56
+ [disabled]="_mutableDisabled()"
57
57
  (dateChange)="_handleChange($event)"
58
58
  />
59
59
  </div>
@@ -70,11 +70,11 @@ export class HlmDatePicker<T> implements ControlValueAccessor {
70
70
  public readonly userClass = input<ClassValue>('', { alias: 'class' });
71
71
  protected readonly _computedClass = computed(() =>
72
72
  hlm(
73
- 'inline-flex items-center gap-2 whitespace-nowrap rounded-md text-sm transition-all disabled:pointer-events-none disabled:opacity-50 ring-offset-background transition-colors border border-input bg-background hover:bg-accent dark:bg-input/30 dark:hover:bg-input/50 hover:text-accent-foreground h-9 px-3 py-2 w-[280px] justify-start text-left font-normal cursor-default justify-between',
73
+ 'inline-flex items-center gap-2 whitespace-nowrap rounded-md text-sm transition-all disabled:pointer-events-none disabled:opacity-50 ring-offset-background border border-input bg-background hover:bg-accent dark:bg-input/30 dark:hover:bg-input/50 hover:text-accent-foreground h-9 px-3 py-2 w-[280px] justify-start text-left font-normal cursor-default justify-between',
74
74
  'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
75
75
  'disabled:pointer-events-none disabled:opacity-50',
76
76
  '[&_ng-icon]:pointer-events-none [&_ng-icon]:shrink-0',
77
- !this.date() ? 'text-muted-foreground' : '',
77
+ !this._mutableDate() ? 'text-muted-foreground' : '',
78
78
  this.userClass(),
79
79
  ),
80
80
  );
@@ -91,7 +91,9 @@ export class HlmDatePicker<T> implements ControlValueAccessor {
91
91
  });
92
92
 
93
93
  /** The selected value. */
94
- public readonly date = model<T>();
94
+ public readonly date = input<T>();
95
+
96
+ protected readonly _mutableDate = linkedSignal(this.date);
95
97
 
96
98
  /** If true, the date picker will close when a date is selected. */
97
99
  public readonly autoCloseOnSelect = input<boolean, BooleanInput>(this._config.autoCloseOnSelect, {
@@ -106,58 +108,53 @@ export class HlmDatePicker<T> implements ControlValueAccessor {
106
108
 
107
109
  protected readonly _popoverState = signal<BrnDialogState | null>(null);
108
110
 
109
- protected readonly _state = computed(() => ({
110
- disabled: signal(this.disabled()),
111
- }));
111
+ protected readonly _mutableDisabled = linkedSignal(this.disabled);
112
112
 
113
113
  protected readonly _formattedDate = computed(() => {
114
- const date = this.date();
114
+ const date = this._mutableDate();
115
115
  return date ? this.formatDate()(date) : undefined;
116
116
  });
117
117
 
118
- public readonly changed = output<T>();
118
+ public readonly dateChange = output<T>();
119
119
 
120
120
  protected _onChange?: ChangeFn<T>;
121
121
  protected _onTouched?: TouchFn;
122
122
 
123
123
  protected _handleChange(value: T) {
124
- if (this._state().disabled()) return;
124
+ if (this._mutableDisabled()) return;
125
125
  const transformedDate = this.transformDate()(value);
126
126
 
127
- this.date.set(transformedDate);
127
+ this._mutableDate.set(transformedDate);
128
128
  this._onChange?.(transformedDate);
129
- this.changed.emit(transformedDate);
129
+ this.dateChange.emit(transformedDate);
130
130
 
131
131
  if (this.autoCloseOnSelect()) {
132
132
  this._popoverState.set('closed');
133
133
  }
134
134
  }
135
135
 
136
- /** CONROL VALUE ACCESSOR */
137
- writeValue(value: T | null): void {
138
- // optional FormControl is initialized with null value
139
- if (value === null) return;
140
-
141
- this.date.set(this.transformDate()(value));
136
+ /** CONTROL VALUE ACCESSOR */
137
+ public writeValue(value: T | null): void {
138
+ this._mutableDate.set(value ? this.transformDate()(value) : undefined);
142
139
  }
143
140
 
144
- registerOnChange(fn: ChangeFn<T>): void {
141
+ public registerOnChange(fn: ChangeFn<T>): void {
145
142
  this._onChange = fn;
146
143
  }
147
144
 
148
- registerOnTouched(fn: TouchFn): void {
145
+ public registerOnTouched(fn: TouchFn): void {
149
146
  this._onTouched = fn;
150
147
  }
151
148
 
152
- setDisabledState(isDisabled: boolean): void {
153
- this._state().disabled.set(isDisabled);
149
+ public setDisabledState(isDisabled: boolean): void {
150
+ this._mutableDisabled.set(isDisabled);
154
151
  }
155
152
 
156
- open() {
153
+ public open() {
157
154
  this._popoverState.set('open');
158
155
  }
159
156
 
160
- close() {
157
+ public close() {
161
158
  this._popoverState.set('closed');
162
159
  }
163
160
  }
@@ -0,0 +1,47 @@
1
+ import { inject, InjectionToken, ValueProvider } from '@angular/core';
2
+
3
+ export interface HlmDateRangePickerConfig<T> {
4
+ /**
5
+ * If true, the date picker will close when the max selection of dates is reached.
6
+ */
7
+ autoCloseOnEndSelection: boolean;
8
+
9
+ /**
10
+ * Defines how the date should be displayed in the UI.
11
+ *
12
+ * @param dates
13
+ * @returns formatted date
14
+ */
15
+ formatDates: (dates: [T | undefined, T | undefined]) => string;
16
+
17
+ /**
18
+ * Defines how the date should be transformed before saving to model/form.
19
+ *
20
+ * @param dates
21
+ * @returns transformed date
22
+ */
23
+ transformDates: (dates: [T, T]) => [T, T];
24
+ }
25
+
26
+ function getDefaultConfig<T>(): HlmDateRangePickerConfig<T> {
27
+ return {
28
+ formatDates: (dates) =>
29
+ dates
30
+ .filter(Boolean)
31
+ .map((date) => (date instanceof Date ? date.toDateString() : `${date}`))
32
+ .join(' - '),
33
+ transformDates: (dates) => dates,
34
+ autoCloseOnEndSelection: false,
35
+ };
36
+ }
37
+
38
+ const HlmDateRangePickerConfigToken = new InjectionToken<HlmDateRangePickerConfig<unknown>>('HlmDateRangePickerConfig');
39
+
40
+ export function provideHlmDateRangePickerConfig<T>(config: Partial<HlmDateRangePickerConfig<T>>): ValueProvider {
41
+ return { provide: HlmDateRangePickerConfigToken, useValue: { ...getDefaultConfig(), ...config } };
42
+ }
43
+
44
+ export function injectHlmDateRangePickerConfig<T>(): HlmDateRangePickerConfig<T> {
45
+ const injectedConfig = inject(HlmDateRangePickerConfigToken, { optional: true });
46
+ return injectedConfig ? (injectedConfig as HlmDateRangePickerConfig<T>) : getDefaultConfig();
47
+ }
@@ -0,0 +1,194 @@
1
+ import { BooleanInput } from '@angular/cdk/coercion';
2
+ import {
3
+ booleanAttribute,
4
+ ChangeDetectionStrategy,
5
+ Component,
6
+ computed,
7
+ forwardRef,
8
+ input,
9
+ linkedSignal,
10
+ output,
11
+ signal,
12
+ untracked,
13
+ } from '@angular/core';
14
+ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
15
+ import { NgIcon, provideIcons } from '@ng-icons/core';
16
+ import { lucideCalendar } from '@ng-icons/lucide';
17
+ import { hlm } from '@spartan-ng/brain/core';
18
+ import { BrnDialogState } from '@spartan-ng/brain/dialog';
19
+ import { type ChangeFn, type TouchFn } from '@spartan-ng/brain/forms';
20
+ import { BrnPopover, BrnPopoverContent, BrnPopoverTrigger } from '@spartan-ng/brain/popover';
21
+ import { HlmCalendarRange } from '@spartan-ng/helm/calendar';
22
+ import { HlmIcon } from '@spartan-ng/helm/icon';
23
+ import { HlmPopoverContent } from '@spartan-ng/helm/popover';
24
+ import type { ClassValue } from 'clsx';
25
+ import { injectHlmDateRangePickerConfig } from './hlm-date-range-picker.token';
26
+
27
+ export const HLM_DATE_RANGE_PICKER_VALUE_ACCESSOR = {
28
+ provide: NG_VALUE_ACCESSOR,
29
+ useExisting: forwardRef(() => HlmDateRangePicker),
30
+ multi: true,
31
+ };
32
+
33
+ @Component({
34
+ selector: 'hlm-date-range-picker',
35
+ imports: [NgIcon, HlmIcon, BrnPopover, BrnPopoverTrigger, BrnPopoverContent, HlmPopoverContent, HlmCalendarRange],
36
+ providers: [HLM_DATE_RANGE_PICKER_VALUE_ACCESSOR, provideIcons({ lucideCalendar })],
37
+ template: `
38
+ <brn-popover
39
+ sideOffset="5"
40
+ [state]="_popoverState()"
41
+ (stateChanged)="_popoverState.set($event)"
42
+ (closed)="_onClose()"
43
+ >
44
+ <button type="button" [class]="_computedClass()" [disabled]="_mutableDisabled()" brnPopoverTrigger>
45
+ <ng-icon hlm size="sm" name="lucideCalendar" />
46
+
47
+ <span class="truncate">
48
+ @if (_formattedDate(); as formattedDate) {
49
+ {{ formattedDate }}
50
+ } @else {
51
+ <ng-content />
52
+ }
53
+ </span>
54
+ </button>
55
+
56
+ <div hlmPopoverContent class="w-auto p-0" *brnPopoverContent="let ctx">
57
+ <hlm-calendar-range
58
+ calendarClass="border-0 rounded-none"
59
+ [startDate]="_start()"
60
+ [endDate]="_end()"
61
+ [min]="min()"
62
+ [max]="max()"
63
+ [disabled]="_mutableDisabled()"
64
+ (startDateChange)="_handleStartDayChange($event)"
65
+ (endDateChange)="_handleEndDateChange($event)"
66
+ />
67
+ </div>
68
+ </brn-popover>
69
+ `,
70
+ host: {
71
+ class: 'block',
72
+ },
73
+ changeDetection: ChangeDetectionStrategy.OnPush,
74
+ })
75
+ export class HlmDateRangePicker<T> implements ControlValueAccessor {
76
+ private readonly _config = injectHlmDateRangePickerConfig<T>();
77
+
78
+ public readonly userClass = input<ClassValue>('', { alias: 'class' });
79
+ protected readonly _computedClass = computed(() =>
80
+ hlm(
81
+ 'inline-flex items-center gap-2 whitespace-nowrap rounded-md text-sm ring-offset-background transition-all border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2 w-[280px] justify-start text-left font-normal',
82
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
83
+ 'disabled:pointer-events-none disabled:opacity-50',
84
+ '[&_ng-icon]:pointer-events-none [&_ng-icon]:shrink-0',
85
+ !this._mutableDate() ? 'text-muted-foreground' : '',
86
+ this.userClass(),
87
+ ),
88
+ );
89
+
90
+ /** The minimum date that can be selected.*/
91
+ public readonly min = input<T>();
92
+
93
+ /** The maximum date that can be selected. */
94
+ public readonly max = input<T>();
95
+
96
+ /** Determine if the date picker is disabled. */
97
+ public readonly disabled = input<boolean, BooleanInput>(false, {
98
+ transform: booleanAttribute,
99
+ });
100
+
101
+ /** The selected value. */
102
+ public readonly date = input<[T, T]>();
103
+
104
+ protected readonly _mutableDate = linkedSignal(this.date);
105
+
106
+ protected readonly _start = linkedSignal(() => this._mutableDate()?.[0]);
107
+ protected readonly _end = linkedSignal(() => this._mutableDate()?.[1]);
108
+
109
+ /** If true, the date picker will close when the end date is selected */
110
+ public readonly autoCloseOnEndSelection = input<boolean, BooleanInput>(this._config.autoCloseOnEndSelection, {
111
+ transform: booleanAttribute,
112
+ });
113
+
114
+ /** Defines how the date should be displayed in the UI. */
115
+ public readonly formatDates = input<(dates: [T | undefined, T | undefined]) => string>(this._config.formatDates);
116
+
117
+ /** Defines how the date should be transformed before saving to model/form. */
118
+ public readonly transformDates = input<(date: [T, T]) => [T, T]>(this._config.transformDates);
119
+
120
+ protected readonly _popoverState = signal<BrnDialogState | null>(null);
121
+
122
+ protected readonly _mutableDisabled = linkedSignal(this.disabled);
123
+
124
+ protected readonly _formattedDate = computed(() => {
125
+ const start = this._start();
126
+ const end = this._end();
127
+ return start || end ? this.formatDates()([start, end]) : undefined;
128
+ });
129
+
130
+ public readonly dateChange = output<[T, T] | null>();
131
+
132
+ protected _onChange?: ChangeFn<[T, T] | null>;
133
+ protected _onTouched?: TouchFn;
134
+
135
+ protected _handleStartDayChange(value: T) {
136
+ this._start.set(value);
137
+ }
138
+
139
+ protected _handleEndDateChange(value: T): void {
140
+ this._end.set(value);
141
+ if (this._mutableDisabled()) return;
142
+
143
+ const start = this._start();
144
+ if (start && value) {
145
+ const transformedDates = this.transformDates()([start, value]);
146
+ this._mutableDate.set(transformedDates);
147
+ this.dateChange.emit(transformedDates);
148
+ this._onChange?.(transformedDates);
149
+
150
+ if (this.autoCloseOnEndSelection()) {
151
+ this._popoverState.set('closed');
152
+ }
153
+ }
154
+ }
155
+
156
+ /** CONTROL VALUE ACCESSOR */
157
+ public writeValue(value: [T, T] | null): void {
158
+ untracked(() => {
159
+ if (!value) {
160
+ this._mutableDate.set(undefined);
161
+ } else {
162
+ this._mutableDate.set(this.transformDates()(value));
163
+ }
164
+ });
165
+ }
166
+
167
+ public registerOnChange(fn: ChangeFn<[T, T] | null>): void {
168
+ this._onChange = fn;
169
+ }
170
+
171
+ public registerOnTouched(fn: TouchFn): void {
172
+ this._onTouched = fn;
173
+ }
174
+
175
+ public setDisabledState(isDisabled: boolean): void {
176
+ this._mutableDisabled.set(isDisabled);
177
+ }
178
+
179
+ public open() {
180
+ this._popoverState.set('open');
181
+ }
182
+
183
+ public close() {
184
+ this._popoverState.set('closed');
185
+ }
186
+
187
+ protected _onClose(): void {
188
+ const dates = this._mutableDate();
189
+ if (this._start() && !this._end() && dates) {
190
+ this._start.set(dates[0]);
191
+ this._end.set(dates[1]);
192
+ }
193
+ }
194
+ }
@@ -6,9 +6,9 @@ import {
6
6
  computed,
7
7
  forwardRef,
8
8
  input,
9
+ linkedSignal,
9
10
  model,
10
11
  output,
11
- signal,
12
12
  } from '@angular/core';
13
13
  import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
14
14
  import { hlm } from '@spartan-ng/brain/core';
@@ -38,7 +38,7 @@ export const HLM_SWITCH_VALUE_ACCESSOR = {
38
38
  [checked]="checked()"
39
39
  (changed)="handleChange($event)"
40
40
  (touched)="_onTouched?.()"
41
- [disabled]="disabled()"
41
+ [disabled]="_disabled()"
42
42
  [id]="id()"
43
43
  [aria-label]="ariaLabel()"
44
44
  [aria-labelledby]="ariaLabelledby()"
@@ -63,9 +63,8 @@ export class HlmSwitch implements ControlValueAccessor {
63
63
  public readonly checked = model<boolean>(false);
64
64
 
65
65
  /** The disabled state of the switch. */
66
- public readonly disabledInput = input<boolean, BooleanInput>(false, {
66
+ public readonly disabled = input<boolean, BooleanInput>(false, {
67
67
  transform: booleanAttribute,
68
- alias: 'disabled',
69
68
  });
70
69
 
71
70
  /** Used to set the id on the underlying brn element. */
@@ -83,9 +82,7 @@ export class HlmSwitch implements ControlValueAccessor {
83
82
  /** Emits when the checked state of the switch changes. */
84
83
  public readonly changed = output<boolean>();
85
84
 
86
- private readonly _writableDisabled = computed(() => signal(this.disabledInput()));
87
-
88
- public readonly disabled = computed(() => this._writableDisabled()());
85
+ protected readonly _disabled = linkedSignal(this.disabled);
89
86
 
90
87
  protected _onChange?: ChangeFn<boolean>;
91
88
  protected _onTouched?: TouchFn;
@@ -111,6 +108,6 @@ export class HlmSwitch implements ControlValueAccessor {
111
108
  }
112
109
 
113
110
  setDisabledState(isDisabled: boolean): void {
114
- this._writableDisabled().set(isDisabled);
111
+ this._disabled.set(isDisabled);
115
112
  }
116
113
  }
@@ -3,7 +3,7 @@
3
3
  "internalName": "ui-accordion-helm",
4
4
  "peerDependencies": {
5
5
  "@angular/core": ">=19.0.0",
6
- "@spartan-ng/brain": "0.0.1-alpha.502",
6
+ "@spartan-ng/brain": "0.0.1-alpha.503",
7
7
  "clsx": "^2.1.1",
8
8
  "@ng-icons/core": ">=29.0.0",
9
9
  "@ng-icons/lucide": ">=29.0.0"
@@ -13,7 +13,7 @@
13
13
  "internalName": "ui-alert-helm",
14
14
  "peerDependencies": {
15
15
  "@angular/core": ">=19.0.0",
16
- "@spartan-ng/brain": "0.0.1-alpha.502",
16
+ "@spartan-ng/brain": "0.0.1-alpha.503",
17
17
  "clsx": "^2.1.1",
18
18
  "class-variance-authority": "^0.7.0"
19
19
  }
@@ -22,7 +22,7 @@
22
22
  "internalName": "ui-alert-dialog-helm",
23
23
  "peerDependencies": {
24
24
  "@angular/core": ">=19.0.0",
25
- "@spartan-ng/brain": "0.0.1-alpha.502",
25
+ "@spartan-ng/brain": "0.0.1-alpha.503",
26
26
  "clsx": "^2.1.1"
27
27
  }
28
28
  },
@@ -31,7 +31,7 @@
31
31
  "peerDependencies": {
32
32
  "@angular/core": ">=19.0.0",
33
33
  "@angular/cdk": ">=19.0.0",
34
- "@spartan-ng/brain": "0.0.1-alpha.502",
34
+ "@spartan-ng/brain": "0.0.1-alpha.503",
35
35
  "clsx": "^2.1.1"
36
36
  }
37
37
  },
@@ -39,7 +39,7 @@
39
39
  "internalName": "ui-avatar-helm",
40
40
  "peerDependencies": {
41
41
  "@angular/core": ">=19.0.0",
42
- "@spartan-ng/brain": "0.0.1-alpha.502",
42
+ "@spartan-ng/brain": "0.0.1-alpha.503",
43
43
  "clsx": "^2.1.1"
44
44
  }
45
45
  },
@@ -47,7 +47,7 @@
47
47
  "internalName": "ui-badge-helm",
48
48
  "peerDependencies": {
49
49
  "@angular/core": ">=19.0.0",
50
- "@spartan-ng/brain": "0.0.1-alpha.502",
50
+ "@spartan-ng/brain": "0.0.1-alpha.503",
51
51
  "class-variance-authority": "^0.7.0",
52
52
  "clsx": "^2.1.1"
53
53
  }
@@ -58,7 +58,7 @@
58
58
  "@angular/core": ">=19.0.0",
59
59
  "@ng-icons/core": ">=29.0.0",
60
60
  "@ng-icons/lucide": ">=29.0.0",
61
- "@spartan-ng/brain": "0.0.1-alpha.502",
61
+ "@spartan-ng/brain": "0.0.1-alpha.503",
62
62
  "clsx": "^2.1.1",
63
63
  "@angular/router": ">=19.0.0"
64
64
  }
@@ -67,7 +67,7 @@
67
67
  "internalName": "ui-button-helm",
68
68
  "peerDependencies": {
69
69
  "@angular/core": ">=19.0.0",
70
- "@spartan-ng/brain": "0.0.1-alpha.502",
70
+ "@spartan-ng/brain": "0.0.1-alpha.503",
71
71
  "class-variance-authority": "^0.7.0",
72
72
  "clsx": "^2.1.1"
73
73
  }
@@ -79,7 +79,7 @@
79
79
  "@angular/cdk": ">=19.0.0",
80
80
  "@ng-icons/core": ">=29.0.0",
81
81
  "@ng-icons/lucide": ">=29.0.0",
82
- "@spartan-ng/brain": "0.0.1-alpha.502",
82
+ "@spartan-ng/brain": "0.0.1-alpha.503",
83
83
  "clsx": "^2.1.1"
84
84
  }
85
85
  },
@@ -87,7 +87,7 @@
87
87
  "internalName": "ui-card-helm",
88
88
  "peerDependencies": {
89
89
  "@angular/core": ">=19.0.0",
90
- "@spartan-ng/brain": "0.0.1-alpha.502",
90
+ "@spartan-ng/brain": "0.0.1-alpha.503",
91
91
  "clsx": "^2.1.1",
92
92
  "class-variance-authority": "^0.7.0"
93
93
  }
@@ -96,7 +96,7 @@
96
96
  "internalName": "ui-carousel-helm",
97
97
  "peerDependencies": {
98
98
  "@angular/core": ">=19.0.0",
99
- "@spartan-ng/brain": "0.0.1-alpha.502",
99
+ "@spartan-ng/brain": "0.0.1-alpha.503",
100
100
  "clsx": "^2.1.1",
101
101
  "@ng-icons/core": ">=29.0.0",
102
102
  "@ng-icons/lucide": ">=29.0.0",
@@ -111,7 +111,7 @@
111
111
  "@angular/forms": ">=19.0.0",
112
112
  "@ng-icons/core": ">=29.0.0",
113
113
  "@ng-icons/lucide": ">=29.0.0",
114
- "@spartan-ng/brain": "0.0.1-alpha.502",
114
+ "@spartan-ng/brain": "0.0.1-alpha.503",
115
115
  "clsx": "^2.1.1"
116
116
  }
117
117
  },
@@ -119,7 +119,7 @@
119
119
  "internalName": "ui-command-helm",
120
120
  "peerDependencies": {
121
121
  "@angular/core": ">=19.0.0",
122
- "@spartan-ng/brain": "0.0.1-alpha.502",
122
+ "@spartan-ng/brain": "0.0.1-alpha.503",
123
123
  "clsx": "^2.1.1",
124
124
  "@angular/cdk": ">=19.0.0"
125
125
  }
@@ -132,7 +132,7 @@
132
132
  "@angular/forms": ">=19.0.0",
133
133
  "@ng-icons/core": ">=29.0.0",
134
134
  "@ng-icons/lucide": ">=29.0.0",
135
- "@spartan-ng/brain": "0.0.1-alpha.502",
135
+ "@spartan-ng/brain": "0.0.1-alpha.503",
136
136
  "clsx": "^2.1.1"
137
137
  }
138
138
  },
@@ -140,7 +140,7 @@
140
140
  "internalName": "ui-dialog-helm",
141
141
  "peerDependencies": {
142
142
  "@angular/core": ">=19.0.0",
143
- "@spartan-ng/brain": "0.0.1-alpha.502",
143
+ "@spartan-ng/brain": "0.0.1-alpha.503",
144
144
  "clsx": "^2.1.1",
145
145
  "@angular/common": ">=19.0.0",
146
146
  "@ng-icons/core": ">=29.0.0",
@@ -153,7 +153,7 @@
153
153
  "peerDependencies": {
154
154
  "@angular/core": ">=19.0.0",
155
155
  "@angular/forms": ">=19.0.0",
156
- "@spartan-ng/brain": "0.0.1-alpha.502",
156
+ "@spartan-ng/brain": "0.0.1-alpha.503",
157
157
  "clsx": "^2.1.1"
158
158
  }
159
159
  },
@@ -161,7 +161,7 @@
161
161
  "internalName": "ui-hover-card-helm",
162
162
  "peerDependencies": {
163
163
  "@angular/core": ">=19.0.0",
164
- "@spartan-ng/brain": "0.0.1-alpha.502",
164
+ "@spartan-ng/brain": "0.0.1-alpha.503",
165
165
  "clsx": "^2.1.1"
166
166
  }
167
167
  },
@@ -177,7 +177,7 @@
177
177
  "internalName": "ui-input-helm",
178
178
  "peerDependencies": {
179
179
  "@angular/core": ">=19.0.0",
180
- "@spartan-ng/brain": "0.0.1-alpha.502",
180
+ "@spartan-ng/brain": "0.0.1-alpha.503",
181
181
  "class-variance-authority": "^0.7.0",
182
182
  "clsx": "^2.1.1",
183
183
  "@angular/forms": ">=19.0.0"
@@ -187,7 +187,7 @@
187
187
  "internalName": "ui-input-otp-helm",
188
188
  "peerDependencies": {
189
189
  "@angular/core": ">=19.0.0",
190
- "@spartan-ng/brain": "0.0.1-alpha.502",
190
+ "@spartan-ng/brain": "0.0.1-alpha.503",
191
191
  "clsx": "^2.1.1",
192
192
  "@ng-icons/core": ">=29.0.0",
193
193
  "@ng-icons/lucide": ">=29.0.0",
@@ -198,7 +198,7 @@
198
198
  "internalName": "ui-label-helm",
199
199
  "peerDependencies": {
200
200
  "@angular/core": ">=19.0.0",
201
- "@spartan-ng/brain": "0.0.1-alpha.502",
201
+ "@spartan-ng/brain": "0.0.1-alpha.503",
202
202
  "clsx": "^2.1.1"
203
203
  }
204
204
  },
@@ -206,7 +206,7 @@
206
206
  "internalName": "ui-menu-helm",
207
207
  "peerDependencies": {
208
208
  "@angular/core": ">=19.0.0",
209
- "@spartan-ng/brain": "0.0.1-alpha.502",
209
+ "@spartan-ng/brain": "0.0.1-alpha.503",
210
210
  "clsx": "^2.1.1",
211
211
  "@ng-icons/core": ">=29.0.0",
212
212
  "@ng-icons/lucide": ">=29.0.0",
@@ -220,7 +220,7 @@
220
220
  "@angular/core": ">=19.0.0",
221
221
  "@angular/cdk": ">=19.0.0",
222
222
  "@angular/forms": ">=19.0.0",
223
- "@spartan-ng/brain": "0.0.1-alpha.502",
223
+ "@spartan-ng/brain": "0.0.1-alpha.503",
224
224
  "class-variance-authority": "^0.7.0",
225
225
  "clsx": "^2.1.1",
226
226
  "@ng-icons/core": ">=29.0.0",
@@ -232,7 +232,7 @@
232
232
  "internalName": "ui-popover-helm",
233
233
  "peerDependencies": {
234
234
  "@angular/core": ">=19.0.0",
235
- "@spartan-ng/brain": "0.0.1-alpha.502",
235
+ "@spartan-ng/brain": "0.0.1-alpha.503",
236
236
  "clsx": "^2.1.1"
237
237
  }
238
238
  },
@@ -240,7 +240,7 @@
240
240
  "internalName": "ui-progress-helm",
241
241
  "peerDependencies": {
242
242
  "@angular/core": ">=19.0.0",
243
- "@spartan-ng/brain": "0.0.1-alpha.502",
243
+ "@spartan-ng/brain": "0.0.1-alpha.503",
244
244
  "clsx": "^2.1.1"
245
245
  }
246
246
  },
@@ -248,7 +248,7 @@
248
248
  "internalName": "ui-radio-group-helm",
249
249
  "peerDependencies": {
250
250
  "@angular/core": ">=19.0.0",
251
- "@spartan-ng/brain": "0.0.1-alpha.502",
251
+ "@spartan-ng/brain": "0.0.1-alpha.503",
252
252
  "clsx": "^2.1.1",
253
253
  "@angular/common": ">=19.0.0"
254
254
  }
@@ -257,7 +257,7 @@
257
257
  "internalName": "ui-scroll-area-helm",
258
258
  "peerDependencies": {
259
259
  "@angular/core": ">=19.0.0",
260
- "@spartan-ng/brain": "0.0.1-alpha.502",
260
+ "@spartan-ng/brain": "0.0.1-alpha.503",
261
261
  "clsx": "^2.1.1"
262
262
  }
263
263
  },
@@ -266,7 +266,7 @@
266
266
  "peerDependencies": {
267
267
  "@angular/core": ">=19.0.0",
268
268
  "@angular/cdk": ">=19.0.0",
269
- "@spartan-ng/brain": "0.0.1-alpha.502",
269
+ "@spartan-ng/brain": "0.0.1-alpha.503",
270
270
  "clsx": "^2.1.1",
271
271
  "@ng-icons/core": ">=29.0.0",
272
272
  "@ng-icons/lucide": ">=29.0.0",
@@ -277,7 +277,7 @@
277
277
  "internalName": "ui-separator-helm",
278
278
  "peerDependencies": {
279
279
  "@angular/core": ">=19.0.0",
280
- "@spartan-ng/brain": "0.0.1-alpha.502",
280
+ "@spartan-ng/brain": "0.0.1-alpha.503",
281
281
  "clsx": "^2.1.1"
282
282
  }
283
283
  },
@@ -285,7 +285,7 @@
285
285
  "internalName": "ui-sheet-helm",
286
286
  "peerDependencies": {
287
287
  "@angular/core": ">=19.0.0",
288
- "@spartan-ng/brain": "0.0.1-alpha.502",
288
+ "@spartan-ng/brain": "0.0.1-alpha.503",
289
289
  "clsx": "^2.1.1",
290
290
  "@ng-icons/core": ">=29.0.0",
291
291
  "@ng-icons/lucide": ">=29.0.0",
@@ -296,7 +296,7 @@
296
296
  "internalName": "ui-skeleton-helm",
297
297
  "peerDependencies": {
298
298
  "@angular/core": ">=19.0.0",
299
- "@spartan-ng/brain": "0.0.1-alpha.502",
299
+ "@spartan-ng/brain": "0.0.1-alpha.503",
300
300
  "clsx": "^2.1.1"
301
301
  }
302
302
  },
@@ -304,7 +304,7 @@
304
304
  "internalName": "ui-slider-helm",
305
305
  "peerDependencies": {
306
306
  "@angular/core": ">=19.0.0",
307
- "@spartan-ng/brain": "0.0.1-alpha.502",
307
+ "@spartan-ng/brain": "0.0.1-alpha.503",
308
308
  "clsx": "^2.1.1"
309
309
  }
310
310
  },
@@ -312,7 +312,7 @@
312
312
  "internalName": "ui-sonner-helm",
313
313
  "peerDependencies": {
314
314
  "@angular/core": ">=19.0.0",
315
- "@spartan-ng/brain": "0.0.1-alpha.502",
315
+ "@spartan-ng/brain": "0.0.1-alpha.503",
316
316
  "clsx": "^2.1.1",
317
317
  "ngx-sonner": ">=3.0.0"
318
318
  }
@@ -321,7 +321,7 @@
321
321
  "internalName": "ui-spinner-helm",
322
322
  "peerDependencies": {
323
323
  "@angular/core": ">=19.0.0",
324
- "@spartan-ng/brain": "0.0.1-alpha.502",
324
+ "@spartan-ng/brain": "0.0.1-alpha.503",
325
325
  "clsx": "^2.1.1"
326
326
  }
327
327
  },
@@ -329,7 +329,7 @@
329
329
  "internalName": "ui-switch-helm",
330
330
  "peerDependencies": {
331
331
  "@angular/core": ">=19.0.0",
332
- "@spartan-ng/brain": "0.0.1-alpha.502",
332
+ "@spartan-ng/brain": "0.0.1-alpha.503",
333
333
  "clsx": "^2.1.1",
334
334
  "@angular/cdk": ">=19.0.0",
335
335
  "@angular/forms": ">=19.0.0"
@@ -339,7 +339,7 @@
339
339
  "internalName": "ui-table-helm",
340
340
  "peerDependencies": {
341
341
  "@angular/core": ">=19.0.0",
342
- "@spartan-ng/brain": "0.0.1-alpha.502",
342
+ "@spartan-ng/brain": "0.0.1-alpha.503",
343
343
  "clsx": "^2.1.1"
344
344
  }
345
345
  },
@@ -347,7 +347,7 @@
347
347
  "internalName": "ui-tabs-helm",
348
348
  "peerDependencies": {
349
349
  "@angular/core": ">=19.0.0",
350
- "@spartan-ng/brain": "0.0.1-alpha.502",
350
+ "@spartan-ng/brain": "0.0.1-alpha.503",
351
351
  "clsx": "^2.1.1",
352
352
  "class-variance-authority": "^0.7.0",
353
353
  "@angular/cdk": ">=19.0.0",
@@ -360,7 +360,7 @@
360
360
  "internalName": "ui-toggle-helm",
361
361
  "peerDependencies": {
362
362
  "@angular/core": ">=19.0.0",
363
- "@spartan-ng/brain": "0.0.1-alpha.502",
363
+ "@spartan-ng/brain": "0.0.1-alpha.503",
364
364
  "class-variance-authority": "^0.7.0",
365
365
  "clsx": "^2.1.1"
366
366
  }
@@ -369,7 +369,7 @@
369
369
  "internalName": "ui-toggle-group-helm",
370
370
  "peerDependencies": {
371
371
  "@angular/core": ">=19.0.0",
372
- "@spartan-ng/brain": "0.0.1-alpha.502",
372
+ "@spartan-ng/brain": "0.0.1-alpha.503",
373
373
  "class-variance-authority": "^0.7.0",
374
374
  "clsx": "^2.1.1"
375
375
  }
@@ -378,14 +378,14 @@
378
378
  "internalName": "ui-tooltip-helm",
379
379
  "peerDependencies": {
380
380
  "@angular/core": ">=19.0.0",
381
- "@spartan-ng/brain": "0.0.1-alpha.502"
381
+ "@spartan-ng/brain": "0.0.1-alpha.503"
382
382
  }
383
383
  },
384
384
  "typography": {
385
385
  "internalName": "ui-typography-helm",
386
386
  "peerDependencies": {
387
387
  "@angular/core": ">=19.0.0",
388
- "@spartan-ng/brain": "0.0.1-alpha.502",
388
+ "@spartan-ng/brain": "0.0.1-alpha.503",
389
389
  "clsx": "^2.1.1"
390
390
  }
391
391
  }