@ng-zen/cli 19.1.0 → 19.2.0-next.1

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 (34) hide show
  1. package/.github/workflows/deploy.yml +13 -5
  2. package/.github/workflows/release.yml +1 -0
  3. package/CHANGELOG.md +14 -0
  4. package/README.md +7 -2
  5. package/angular.json +2 -2
  6. package/eslint.config.js +34 -1
  7. package/package.json +44 -49
  8. package/src/schematics/components/components-generator.ts +1 -1
  9. package/src/schematics/components/files/button/button.component.scss +6 -5
  10. package/src/schematics/components/files/button/button.stories.ts +1 -0
  11. package/src/schematics/components/files/checkbox/checkbox.component.scss +1 -1
  12. package/src/schematics/components/files/checkbox/checkbox.component.ts +1 -1
  13. package/src/schematics/components/files/checkbox/checkbox.stories.ts +1 -0
  14. package/src/schematics/components/files/divider/divider.component.scss +52 -0
  15. package/src/schematics/components/files/divider/divider.component.spec.ts +22 -0
  16. package/src/schematics/components/files/divider/divider.component.ts +58 -0
  17. package/src/schematics/components/files/divider/divider.stories.ts +69 -0
  18. package/src/schematics/components/files/divider/index.ts +1 -0
  19. package/src/schematics/components/files/input/input.component.scss +1 -1
  20. package/src/schematics/components/files/input/input.stories.ts +1 -0
  21. package/src/schematics/components/files/switch/switch.component.scss +2 -2
  22. package/src/schematics/components/files/switch/switch.stories.ts +1 -0
  23. package/src/schematics/components/files/textarea/textarea.component.scss +1 -1
  24. package/src/schematics/components/files/textarea/textarea.stories.ts +1 -0
  25. package/src/schematics/components/schema.json +1 -1
  26. package/src/schematics/ng-add/index.ts +4 -6
  27. package/src/schematics/ng-add/ng-zen-generator.ts +3 -3
  28. package/src/utils/apply-file-template.util.ts +1 -0
  29. package/src/utils/index.ts +0 -1
  30. package/projects/schematic-builder/builders/builders.json +0 -9
  31. package/projects/schematic-builder/builders/index.js +0 -100
  32. package/projects/schematic-builder/builders/schema.json +0 -18
  33. package/projects/schematic-builder/package.json +0 -11
  34. package/src/utils/add-path-to-tsconfig.util.ts +0 -50
@@ -2,7 +2,8 @@ name: Deploy Storybook to github pages
2
2
 
3
3
  on:
4
4
  push:
5
- branches: ["master"]
5
+ tags:
6
+ - 'v*.*.*'
6
7
  workflow_dispatch:
7
8
 
8
9
  env:
@@ -18,14 +19,21 @@ jobs:
18
19
  deploy:
19
20
  runs-on: ubuntu-latest
20
21
  steps:
21
- - uses: actions/checkout@v4 # Checkout your repository
22
- - uses: pnpm/action-setup@v4
22
+ - name: Checkout code
23
+ uses: actions/checkout@v4
24
+ - name: Enable Corepack
25
+ run: corepack enable
26
+ - name: Setup pnpm
27
+ uses: pnpm/action-setup@v4
23
28
  with:
24
29
  version: ${{ env.PNPM_VERSION }}
25
- - uses: actions/setup-node@v4
30
+ - name: Setup Node.js
31
+ uses: actions/setup-node@v4
26
32
  with:
27
33
  node-version: ${{ env.NODE_VERSION }}
28
- - id: build-publish
34
+ cache: 'pnpm'
35
+ - name: Build and deploy Storybook
36
+ id: build-publish
29
37
  uses: bitovi/github-actions-storybook-to-github-pages@v1.0.3
30
38
  with:
31
39
  install_command: pnpm install --frozen-lockfile
@@ -20,6 +20,7 @@ jobs:
20
20
  - name: Checkout code
21
21
  uses: actions/checkout@v4
22
22
  with:
23
+ persist-credentials: false
23
24
  fetch-depth: 0
24
25
  fetch-tags: true
25
26
  - name: Enable Corepack
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 19.2.0-next.1 (2025-05-23)
2
+
3
+ * chore(dependencies): update dependencies (#187) ([7028a9e](https://github.com/kstepien3/ng-zen/commit/7028a9e)), closes [#187](https://github.com/kstepien3/ng-zen/issues/187)
4
+ * chore(dependencies): update ngx-schematic-builder to v0.2.0 (#183) ([5ea0cea](https://github.com/kstepien3/ng-zen/commit/5ea0cea)), closes [#183](https://github.com/kstepien3/ng-zen/issues/183)
5
+ * chore(workflow): update deploy workflow for tag-based triggering (#166) ([0fea522](https://github.com/kstepien3/ng-zen/commit/0fea522)), closes [#166](https://github.com/kstepien3/ng-zen/issues/166) [#165](https://github.com/kstepien3/ng-zen/issues/165)
6
+ * chore(workflows): disable persist-credentials in release workflow (#188) ([b784e47](https://github.com/kstepien3/ng-zen/commit/b784e47)), closes [#188](https://github.com/kstepien3/ng-zen/issues/188)
7
+ * feat(divider): add zen-divider component (#186) ([c021773](https://github.com/kstepien3/ng-zen/commit/c021773)), closes [#186](https://github.com/kstepien3/ng-zen/issues/186)
8
+ * style(components): update outline styles (#184) ([5737a15](https://github.com/kstepien3/ng-zen/commit/5737a15)), closes [#184](https://github.com/kstepien3/ng-zen/issues/184)
9
+ * fix(schematics/ng-add): run other schematics after installation (#177) ([5cb1be4](https://github.com/kstepien3/ng-zen/commit/5cb1be4)), closes [#177](https://github.com/kstepien3/ng-zen/issues/177)
10
+ * ci(eslint): fix plugins and configure linting rules (#176) ([5e93a09](https://github.com/kstepien3/ng-zen/commit/5e93a09)), closes [#176](https://github.com/kstepien3/ng-zen/issues/176)
11
+ * build(deps-dev): bump typescript from 5.7.3 to 5.8.3 (#154) ([3ebe49f](https://github.com/kstepien3/ng-zen/commit/3ebe49f)), closes [#154](https://github.com/kstepien3/ng-zen/issues/154)
12
+ * build(ngx-schematic-builder): migrate the custom builder (#175) ([c7d19eb](https://github.com/kstepien3/ng-zen/commit/c7d19eb)), closes [#175](https://github.com/kstepien3/ng-zen/issues/175)
13
+ * Merge remote-tracking branch 'origin/next' into develop ([f581d01](https://github.com/kstepien3/ng-zen/commit/f581d01))
14
+
1
15
  ## [19.1.0](https://github.com/kstepien3/ng-zen/compare/v19.0.0...v19.1.0) (2025-04-27)
2
16
 
3
17
  ### 🚀 New Features
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  Generate modern, customizable Angular UI components and elements directly into your project 🚀
13
13
 
14
- Built with best practices and developer experience in mind 💡
14
+ Built with the best practices and developer experience in mind 💡
15
15
 
16
16
  ## Table of Contents
17
17
 
@@ -27,7 +27,8 @@ Built with best practices and developer experience in mind 💡
27
27
  10. [Contributing](#contributing)
28
28
  11. [License](#license)
29
29
  12. [Author](#author)
30
- 13. [FAQ](#faq)
30
+ 13. [See also](#see-also)
31
+ 14. [FAQ](#faq)
31
32
 
32
33
  ## Features
33
34
 
@@ -148,6 +149,10 @@ Maintained by Konrad Stępień.
148
149
  - LinkedIn: [Konrad Stępień](https://www.linkedin.com/in/konradstepien/) 👥
149
150
  - Email: [kord.stp@gmail.com](mailto:kord.stp@gmail.com?subject=%5BNG-ZEN%5D%20Query) 📨
150
151
 
152
+ ## See also
153
+
154
+ - [ngx-schematic-builder](https://github.com/kstepien3/ngx-schematic-builder) - A custom Angular builder for compiling and bundling Angular schematics.
155
+
151
156
  ## FAQ
152
157
 
153
158
  ### How do I customize a generated component?
package/angular.json CHANGED
@@ -20,9 +20,9 @@
20
20
  "prefix": "zen",
21
21
  "architect": {
22
22
  "build": {
23
- "builder": "./projects/schematic-builder:build",
23
+ "builder": "ngx-schematic-builder:build",
24
24
  "options": {
25
- "files": ["src/**", "README.md", "package.json", "LICENSE", "CHANGELOG.md"],
25
+ "files": ["src/**", "README.md", "LICENSE", "CHANGELOG.md"],
26
26
  "tsConfig": "tsconfig.schematics.json"
27
27
  }
28
28
  },
package/eslint.config.js CHANGED
@@ -2,8 +2,15 @@
2
2
  const eslint = require('@eslint/js');
3
3
  const tseslint = require('typescript-eslint');
4
4
  const angular = require('angular-eslint');
5
+ const prettierRecommended = require('eslint-plugin-prettier/recommended');
6
+ const eslintPluginImport = require('eslint-plugin-import');
7
+ const simpleImportSort = require('eslint-plugin-simple-import-sort');
8
+ const unicorn = require('eslint-plugin-unicorn');
9
+ const unusedImports = require('eslint-plugin-unused-imports');
10
+ const storybook = require('eslint-plugin-storybook');
5
11
 
6
12
  module.exports = tseslint.config(
13
+ ...storybook.configs['flat/recommended'],
7
14
  {
8
15
  files: ['**/*.ts'],
9
16
  extends: [
@@ -13,6 +20,12 @@ module.exports = tseslint.config(
13
20
  ...angular.configs.tsRecommended,
14
21
  ],
15
22
  processor: angular.processInlineTemplates,
23
+ plugins: {
24
+ 'simple-import-sort': simpleImportSort,
25
+ 'import/recommended': eslintPluginImport.flatConfigs,
26
+ unicorn: unicorn,
27
+ 'unused-imports': unusedImports,
28
+ },
16
29
  rules: {
17
30
  '@angular-eslint/directive-selector': [
18
31
  'error',
@@ -30,11 +43,31 @@ module.exports = tseslint.config(
30
43
  style: 'kebab-case',
31
44
  },
32
45
  ],
46
+ 'simple-import-sort/imports': 'warn',
47
+ 'simple-import-sort/exports': 'warn',
48
+ 'unused-imports/no-unused-imports': 'warn',
33
49
  },
34
50
  },
35
51
  {
36
52
  files: ['**/*.html'],
37
53
  extends: [...angular.configs.templateRecommended, ...angular.configs.templateAccessibility],
38
- rules: {},
54
+ rules: {
55
+ '@angular-eslint/template/prefer-self-closing-tags': ['error'],
56
+ },
57
+ },
58
+ {
59
+ files: ['**/*.html', '**/*.ts'],
60
+ extends: [prettierRecommended],
61
+ rules: {
62
+ 'prettier/prettier': [
63
+ 'warn',
64
+ {
65
+ endOfLine: 'auto',
66
+ },
67
+ ],
68
+ },
69
+ },
70
+ {
71
+ ignores: ['!.storybook'],
39
72
  }
40
73
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-zen/cli",
3
- "version": "19.1.0",
3
+ "version": "19.2.0-next.1",
4
4
  "description": "A CLI tool for generating customizable, modern Angular UI components using schematics.",
5
5
  "scripts": {
6
6
  "ng": "ng",
@@ -55,77 +55,72 @@
55
55
  "@angular/core": ">=19.0.0"
56
56
  },
57
57
  "dependencies": {
58
- "@angular-devkit/core": "^19.1.7",
59
- "@angular-devkit/schematics": "^19.1.7",
58
+ "@angular-devkit/core": "^19.2.13",
59
+ "@angular-devkit/schematics": "^19.2.13",
60
60
  "tslib": "^2.8.1"
61
61
  },
62
62
  "devDependencies": {
63
- "@angular-builders/jest": "^19.0.0",
64
- "@angular-devkit/architect": "^0.1902.6",
65
- "@angular-devkit/build-angular": "^19.1.5",
63
+ "@angular-builders/jest": "^19.0.1",
64
+ "@angular-devkit/architect": "^0.1902.13",
65
+ "@angular-devkit/build-angular": "^19.2.13",
66
66
  "@angular-devkit/core": "^19.1.7",
67
- "@angular/animations": "^19.1.5",
68
- "@angular/cli": "^19.1.7",
69
- "@angular/common": "^19.1.5",
70
- "@angular/compiler": "^19.1.5",
71
- "@angular/compiler-cli": "^19.1.5",
72
- "@angular/core": "^19.1.5",
73
- "@angular/forms": "^19.1.5",
74
- "@angular/platform-browser": "^19.1.5",
75
- "@angular/platform-browser-dynamic": "^19.1.5",
76
- "@angular/router": "^19.1.5",
67
+ "@angular/animations": "^19.2.12",
68
+ "@angular/cli": "^19.2.13",
69
+ "@angular/common": "^19.2.12",
70
+ "@angular/compiler": "^19.2.12",
71
+ "@angular/compiler-cli": "^19.2.12",
72
+ "@angular/core": "^19.2.12",
73
+ "@angular/forms": "^19.2.12",
74
+ "@angular/platform-browser": "^19.2.12",
75
+ "@angular/platform-browser-dynamic": "^19.2.12",
76
+ "@angular/router": "^19.2.12",
77
77
  "@chromatic-com/storybook": "^3.2.6",
78
- "@commitlint/cli": "^19.7.1",
79
- "@commitlint/config-conventional": "^19.8.0",
78
+ "@commitlint/cli": "^19.8.1",
79
+ "@commitlint/config-conventional": "^19.8.1",
80
80
  "@compodoc/compodoc": "^1.1.26",
81
- "@eslint/js": "^9.22.0",
81
+ "@eslint/js": "^9.27.0",
82
82
  "@semantic-release/changelog": "^6.0.3",
83
83
  "@semantic-release/commit-analyzer": "^13.0.1",
84
84
  "@semantic-release/git": "^10.0.1",
85
- "@semantic-release/github": "^11.0.1",
85
+ "@semantic-release/github": "^11.0.2",
86
86
  "@semantic-release/npm": "^12.0.1",
87
87
  "@semantic-release/release-notes-generator": "^14.0.3",
88
- "@storybook/addon-docs": "^8.5.5",
89
- "@storybook/addon-essentials": "^8.5.5",
90
- "@storybook/addon-interactions": "^8.5.5",
91
- "@storybook/addon-links": "^8.6.12",
92
- "@storybook/addon-onboarding": "^8.5.5",
93
- "@storybook/angular": "^8.5.3",
94
- "@storybook/blocks": "^8.5.3",
95
- "@storybook/test": "^8.5.5",
88
+ "@storybook/addon-docs": "^8.6.14",
89
+ "@storybook/addon-essentials": "^8.6.14",
90
+ "@storybook/addon-interactions": "^8.6.14",
91
+ "@storybook/addon-links": "^8.6.14",
92
+ "@storybook/addon-onboarding": "^8.6.14",
93
+ "@storybook/angular": "^8.6.14",
94
+ "@storybook/blocks": "^8.6.14",
95
+ "@storybook/test": "^8.6.14",
96
96
  "@types/jest": "29.5.14",
97
- "angular-eslint": "19.3.0",
98
- "conventional-changelog-conventionalcommits": "^8.0.0",
97
+ "angular-eslint": "19.4.0",
99
98
  "copyfiles": "^2.4.1",
100
99
  "cpy": "^11.1.0",
101
- "eslint": "^9.20.0",
102
- "eslint-config-prettier": "^10.0.1",
100
+ "eslint": "^9.27.0",
101
+ "eslint-config-prettier": "^10.1.5",
103
102
  "eslint-plugin-import": "^2.31.0",
104
- "eslint-plugin-prettier": "^5.2.3",
103
+ "eslint-plugin-prettier": "^5.4.0",
105
104
  "eslint-plugin-simple-import-sort": "^12.1.1",
106
105
  "eslint-plugin-storybook": "^0.12.0",
107
- "eslint-plugin-unicorn": "^57.0.0",
106
+ "eslint-plugin-unicorn": "^59.0.1",
108
107
  "eslint-plugin-unused-imports": "^4.1.4",
109
- "execa": "^9.5.2",
108
+ "execa": "^9.5.3",
110
109
  "fs-extra": "^11.3.0",
111
110
  "husky": "^9.1.7",
112
- "jasmine-core": "~5.6.0",
111
+ "jasmine-core": "~5.7.1",
113
112
  "jest": "^29.7.0",
114
- "jest-preset-angular": "^14.5.4",
113
+ "jest-preset-angular": "^14.5.5",
115
114
  "nano-staged": "^0.8.0",
115
+ "ngx-schematic-builder": "^0.2.0",
116
116
  "prettier": "^3.5.3",
117
117
  "prettier-plugin-organize-attributes": "^1.0.0",
118
- "rxjs": "~7.8.1",
119
- "semantic-release": "^24.2.3",
120
- "storybook": "^8.5.5",
121
- "stylelint": "^16.17.0",
122
- "stylelint-config-standard-scss": "^14.0.0",
123
- "typescript": "~5.7.3",
124
- "typescript-eslint": "8.29.1"
125
- },
126
- "eslintConfig": {
127
- "extends": [
128
- "plugin:storybook/recommended"
129
- ]
118
+ "rxjs": "~7.8.2",
119
+ "semantic-release": "^24.2.4",
120
+ "storybook": "^8.6.14",
121
+ "stylelint": "^16.19.1",
122
+ "stylelint-config-standard-scss": "^15.0.1",
123
+ "typescript": "~5.8.3",
124
+ "typescript-eslint": "8.32.1"
130
125
  }
131
126
  }
@@ -1,6 +1,6 @@
1
1
  import { GeneratorSchemaBase } from '../../types';
2
2
 
3
- export type ComponentType = 'avatar' | 'button' | 'checkbox' | 'input' | 'switch' | 'textarea';
3
+ export type ComponentType = 'avatar' | 'button' | 'checkbox' | 'divider' | 'input' | 'switch' | 'textarea';
4
4
 
5
5
  export interface ComponentGeneratorSchema extends GeneratorSchemaBase {
6
6
  components: ComponentType[];
@@ -2,9 +2,9 @@ $bg-color-hover: #333;
2
2
  $bg-color: #000;
3
3
  $color: #fff;
4
4
  $padding: 8px 24px;
5
- $shadow-hover: 0 0 0 3px rgb(0 123 255 / 50%);
6
5
  $shadow: 0 2px 4px rgb(0 0 0 / 10%);
7
6
  $transition-duration: 0.4s;
7
+ $outline: var(--zen-outline, 2px solid hsl(200deg 100 50 / 50%));
8
8
 
9
9
  :host {
10
10
  display: inline-block;
@@ -15,12 +15,13 @@ $transition-duration: 0.4s;
15
15
  border: none;
16
16
  padding: $padding;
17
17
  border-radius: 99999px;
18
- transition: all $transition-duration ease;
18
+ transition-property: background-color, opacity;
19
+ transition-duration: $transition-duration;
20
+ transition-timing-function: ease;
19
21
  background-color: $bg-color;
20
22
  color: $color;
21
23
  box-shadow: $shadow;
22
24
  text-decoration: none;
23
- outline: none;
24
25
  overflow: hidden;
25
26
  position: relative;
26
27
  }
@@ -31,8 +32,8 @@ $transition-duration: 0.4s;
31
32
  }
32
33
 
33
34
  /* Focus state */
34
- :host:focus {
35
- box-shadow: $shadow-hover;
35
+ :host:focus-visible {
36
+ outline: $outline;
36
37
  }
37
38
 
38
39
  /* Disabled state */
@@ -1,4 +1,5 @@
1
1
  import type { Meta, StoryObj } from '@storybook/angular';
2
+
2
3
  import { ZenButtonComponent } from './button.component';
3
4
 
4
5
  export default {
@@ -8,7 +8,7 @@ $appearance: var(--zen-checkbox-appearance, hsl(0% 0% 10%));
8
8
  $disabled-opacity: var(--zen-checkbox-disabled-opacity, 0.6);
9
9
  $border: var(--zen-checkbox-border, 1px solid hsl(0% 0% 80%));
10
10
  $error: var(--zen-error, hsl(0% 70% 50%));
11
- $outline: var(--zen-outline, 1px solid hsl(0% 0% 60%));
11
+ $outline: var(--zen-outline, 2px solid hsl(200deg 100 50 / 50%));
12
12
 
13
13
  // Animations
14
14
  $transition-duration: var(--zen-transition-duration, 0.2s);
@@ -1,5 +1,5 @@
1
- import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
2
1
  import { booleanAttribute, ChangeDetectionStrategy, Component, forwardRef, input, model } from '@angular/core';
2
+ import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
3
3
 
4
4
  /**
5
5
  * ZenCheckboxComponent is a reusable checkbox component designed to provide
@@ -1,4 +1,5 @@
1
1
  import { Meta, StoryObj } from '@storybook/angular';
2
+
2
3
  import { ZenCheckboxComponent } from './checkbox.component';
3
4
 
4
5
  export default {
@@ -0,0 +1,52 @@
1
+ $appearance: var(--zen-divider-appearance, hsl(0% 0% 10%));
2
+ $type: var(--zen-divider-type, solid);
3
+ $align-offset: var(--zen-divider-align-offset, 25%);
4
+ $gap: var(--zen-divider-gap, 0.25rem);
5
+ $thickness: var(--zen-divider-thickness, 1px);
6
+
7
+ :host {
8
+ width: 100%;
9
+ display: flex;
10
+ align-items: center;
11
+ gap: $gap;
12
+
13
+ &::before,
14
+ &::after {
15
+ content: '';
16
+ display: block;
17
+ width: 100%;
18
+ height: 0;
19
+ border-color: $appearance;
20
+ border-style: $type;
21
+ border-width: #{$thickness} 0 0;
22
+ }
23
+
24
+ &:not(.has-content)::after {
25
+ content: none;
26
+ }
27
+
28
+ &.zen-align-start::before,
29
+ &.zen-align-end::after {
30
+ width: $align-offset;
31
+ }
32
+ }
33
+
34
+ :host[vertical]:not([vertical='false']) {
35
+ flex-direction: column;
36
+ width: unset;
37
+ height: 100%;
38
+
39
+ &::before,
40
+ &::after {
41
+ content: '';
42
+ display: block;
43
+ width: unset;
44
+ height: 100%;
45
+ border-width: 0 #{$thickness} 0 0;
46
+ }
47
+
48
+ &.zen-align-start::before,
49
+ &.zen-align-end::after {
50
+ height: $align-offset;
51
+ }
52
+ }
@@ -0,0 +1,22 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { ZenDividerComponent } from './divider.component';
4
+
5
+ describe('DividerComponent', () => {
6
+ let component: ZenDividerComponent;
7
+ let fixture: ComponentFixture<ZenDividerComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [ZenDividerComponent],
12
+ }).compileComponents();
13
+
14
+ fixture = TestBed.createComponent(ZenDividerComponent);
15
+ component = fixture.componentInstance;
16
+ fixture.detectChanges();
17
+ });
18
+
19
+ it('should create', () => {
20
+ expect(component).toBeTruthy();
21
+ });
22
+ });
@@ -0,0 +1,58 @@
1
+ import { ChangeDetectionStrategy, Component, computed, ElementRef, inject, input } from '@angular/core';
2
+
3
+ /**
4
+ * ZenDividerComponent is a reusable divider component that provides a simple way to
5
+ * separate content sections visually. It supports both horizontal (default) and vertical
6
+ * orientations and can contain optional content.
7
+ *
8
+ * The divider automatically detects if it contains content and applies appropriate styling.
9
+ * Content alignment can be controlled via the `align` input property.
10
+ *
11
+ * @example
12
+ * ```html
13
+ * <zen-divider/>
14
+ * <zen-divider>With content</zen-divider>
15
+ * ```
16
+ *
17
+ * ### CSS Custom Properties
18
+ * You can customize the component using CSS custom properties:
19
+ *
20
+ * ```css
21
+ * :root {
22
+ * --zen-divider-appearance: red;
23
+ * --zen-divider-type: dotted;
24
+ * --zen-divider-align-offset: 10%;
25
+ * }
26
+ * ```
27
+ *
28
+ * @author Konrad Stępień
29
+ * @license {@link https://github.com/kstepien3/ng-zen/blob/master/LICENSE|BSD-2-Clause}
30
+ * @see [GitHub](https://github.com/kstepien3/ng-zen)
31
+ */
32
+ @Component({
33
+ selector: `zen-divider, zen-divider[vertical],`,
34
+ template: '<ng-content/>',
35
+ styleUrl: './divider.component.scss',
36
+ changeDetection: ChangeDetectionStrategy.OnPush,
37
+ host: {
38
+ '[class.has-content]': 'hasContent()',
39
+ '[class]': '"zen-align-"+align()',
40
+ },
41
+ })
42
+ export class ZenDividerComponent {
43
+ /**
44
+ * Controls the alignment of content within the divider.
45
+ * @default 'center'
46
+ */
47
+ readonly align = input<'start' | 'end' | 'center'>('center');
48
+
49
+ /**
50
+ * Computed property that determines if the divider contains any content.
51
+ * Used to apply appropriate styling when content is present.
52
+ */
53
+ readonly hasContent = computed(() => {
54
+ return this.elementRef.nativeElement.childNodes.length > 0;
55
+ });
56
+
57
+ private readonly elementRef = inject(ElementRef);
58
+ }
@@ -0,0 +1,69 @@
1
+ import { Meta, StoryObj } from '@storybook/angular';
2
+
3
+ import { ZenDividerComponent } from './divider.component';
4
+
5
+ interface StoryParams {
6
+ content: string;
7
+ vertical: boolean;
8
+ }
9
+
10
+ export default {
11
+ title: 'Components/Divider',
12
+ component: ZenDividerComponent,
13
+ tags: ['autodocs'],
14
+ parameters: {
15
+ layout: 'padded',
16
+ },
17
+ argTypes: {
18
+ content: { control: 'text' },
19
+ vertical: { control: 'boolean' },
20
+ align: { control: 'select', options: ['start', 'center', 'end'] },
21
+ },
22
+ args: { content: '', vertical: false, align: 'center' },
23
+ } satisfies Meta<ZenDividerComponent & StoryParams>;
24
+
25
+ type Story = StoryObj<ZenDividerComponent & StoryParams>;
26
+
27
+ export const Default: Story = {
28
+ render: args => ({
29
+ props: { ...args },
30
+ template: `
31
+ <div style="height: 200px">
32
+ <zen-divider [align]="'${args.align}'" [attr.vertical]="${args.vertical}">
33
+ ${args.content ?? ''}
34
+ </zen-divider>
35
+ </div>`,
36
+ }),
37
+ };
38
+
39
+ export const Vertical: Story = {
40
+ render: args => ({
41
+ props: { ...args },
42
+ template: `
43
+ <div style="height: 200px; display: flex; justify-content: space-between">
44
+ <zen-divider vertical align="start">
45
+ START
46
+ </zen-divider>
47
+ <zen-divider vertical>
48
+ CENTER
49
+ </zen-divider>
50
+ <zen-divider vertical align="end">
51
+ END
52
+ </zen-divider>
53
+ </div>`,
54
+ }),
55
+ };
56
+
57
+ export const Customization: Story = {
58
+ render: () => ({
59
+ template: `
60
+ <div style="display: flex; flex-direction: column; gap: 1rem">
61
+ <zen-divider style="--zen-divider-appearance: red;">appearance</zen-divider>
62
+ <zen-divider style="--zen-divider-type: dotted;">type</zen-divider>
63
+ <zen-divider style="--zen-divider-align-offset: 10%;" align="start">offset</zen-divider>
64
+ <zen-divider style="--zen-divider-gap: 50px">gap</zen-divider>
65
+ <zen-divider style="--zen-divider-thickness: 8px">offset</zen-divider>
66
+ </div>
67
+ `,
68
+ }),
69
+ };
@@ -0,0 +1 @@
1
+ export * from './divider.component';
@@ -6,7 +6,7 @@ $focus-shadow: var(--zen-input-focus-shadow, 0 1px 4px hsla(0% 0% 60% / 20%) ins
6
6
  $placeholder-color: var(--zen-input-placeholder-color, hsl(0% 0% 60%));
7
7
 
8
8
  // Color Palette
9
- $outline: var(--zen-outline, 1px solid hsl(0% 0% 60%));
9
+ $outline: var(--zen-outline, 2px solid hsl(200deg 100 50 / 50%));
10
10
  $error: var(--zen-error, hsl(0% 70% 50%));
11
11
 
12
12
  input {
@@ -1,4 +1,5 @@
1
1
  import { Meta, StoryObj } from '@storybook/angular';
2
+
2
3
  import { ZenInputComponent } from './input.component';
3
4
 
4
5
  export default {
@@ -1,4 +1,4 @@
1
- $outline: var(--zen-outline, 2px solid hsl(0% 0% 60%));
1
+ $outline: var(--zen-outline, 2px solid hsl(200deg 100 50 / 50%));
2
2
  $transition-duration: 0.15s;
3
3
  $placeholder-color: var(--zen-input-placeholder-color, hsl(0% 0% 60%));
4
4
  $size: var(--zen-switch-size, 16px);
@@ -43,7 +43,7 @@ $height: calc(#{$size} + #{$margin} * 2);
43
43
  width: calc(#{$size} + 2px);
44
44
  }
45
45
 
46
- &:focus {
46
+ &:focus-visible {
47
47
  outline: $outline;
48
48
  }
49
49
 
@@ -1,4 +1,5 @@
1
1
  import { Meta, StoryObj } from '@storybook/angular';
2
+
2
3
  import { ZenSwitchComponent } from './switch.component';
3
4
 
4
5
  export default {
@@ -6,7 +6,7 @@ $focus-shadow: var(--zen-input-focus-shadow, 0 1px 4px hsla(0% 0% 60% / 20%) ins
6
6
  $placeholder-color: var(--zen-input-placeholder-color, hsl(0% 0% 60%));
7
7
 
8
8
  // Color Palette
9
- $outline: var(--zen-outline, 1px solid hsl(0% 0% 60%));
9
+ $outline: var(--zen-outline, 2px solid hsl(200deg 100 50 / 50%));
10
10
  $error: var(--zen-error, hsl(0% 70% 50%));
11
11
 
12
12
  :host {
@@ -1,4 +1,5 @@
1
1
  import { Meta, StoryObj } from '@storybook/angular';
2
+
2
3
  import { ZenTextareaComponent } from './textarea.component';
3
4
 
4
5
  interface StoryParams {
@@ -10,7 +10,7 @@
10
10
  "type": "array",
11
11
  "items": {
12
12
  "type": "string",
13
- "enum": ["avatar", "button", "checkbox", "input", "switch", "textarea"]
13
+ "enum": ["avatar", "button", "checkbox", "divider", "input", "switch", "textarea"]
14
14
  },
15
15
  "multiselect": true,
16
16
  "x-prompt": "Which component should be generated?"
@@ -1,14 +1,12 @@
1
- import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
1
+ import { chain, Rule, schematic, SchematicContext, Tree } from '@angular-devkit/schematics';
2
2
 
3
- import { addPathToTsconfigUtil } from '../../utils';
4
3
  import { NgZenGeneratorSchema } from './ng-zen-generator';
5
4
 
6
5
  export function ngAdd(options: NgZenGeneratorSchema): Rule {
7
- return (tree: Tree, _context: SchematicContext) => {
6
+ return (_tree: Tree, _context: SchematicContext) => {
8
7
  _context.logger.info('Adding library to the project');
9
8
 
10
- addPathToTsconfigUtil(tree, 'ng-zen/*', [`${options.path}/*`]);
11
-
12
- return tree;
9
+ // Run other schematics from ng-add
10
+ return chain([schematic('component', options)]);
13
11
  };
14
12
  }
@@ -1,3 +1,3 @@
1
- export interface NgZenGeneratorSchema {
2
- path: string;
3
- }
1
+ import { GeneratorSchemaBase } from '../../types';
2
+
3
+ export type NgZenGeneratorSchema = GeneratorSchemaBase;
@@ -1,5 +1,6 @@
1
1
  import { normalize, strings } from '@angular-devkit/core';
2
2
  import { apply, applyTemplates, chain, filter, mergeWith, move, Rule, url } from '@angular-devkit/schematics';
3
+
3
4
  import { GeneratorSchemaBase } from '../types';
4
5
  import { SchematicsFolder } from '../types/schematics-folder.type';
5
6
 
@@ -1,2 +1 @@
1
- export * from './add-path-to-tsconfig.util';
2
1
  export * from './apply-file-template.util';
@@ -1,9 +0,0 @@
1
- {
2
- "builders": {
3
- "build": {
4
- "implementation": "./index.js",
5
- "schema": "./schema.json",
6
- "description": "Custom builder for angular schematics"
7
- }
8
- }
9
- }
@@ -1,100 +0,0 @@
1
- import { createBuilder } from '@angular-devkit/architect';
2
- import { execa } from 'execa';
3
- import cpy from 'cpy';
4
- import path from 'node:path';
5
- import fs from 'fs-extra';
6
-
7
- const LOG = {
8
- log: (logger, level, type, message) => {
9
- const timestamp = new Date().toISOString();
10
- const output = `[${timestamp}] [${type}] ${message}`;
11
-
12
- // Use the appropriate logger method based on the log level
13
- switch (level) {
14
- case 'INFO':
15
- logger.info(output);
16
- break;
17
- case 'ERROR':
18
- logger.error(output);
19
- break;
20
- default:
21
- logger.log(output);
22
- }
23
- },
24
-
25
- info: (logger, type, message) => LOG.log(logger, 'INFO', type, message),
26
- error: (logger, type, message) => LOG.log(logger, 'ERROR', type, message),
27
- };
28
- async function cleanOutputDirectory(outputDir, context) {
29
- try {
30
- if (await fs.pathExists(outputDir)) {
31
- await fs.rm(outputDir, { recursive: true, force: true });
32
- }
33
- await fs.mkdir(outputDir, { recursive: true });
34
- } catch (error) {
35
- LOG.error(context.logger, 'ERROR', `Failed to clean output directory: ${error.message}`);
36
- context.logger.error();
37
- throw error;
38
- }
39
- }
40
-
41
- async function getOutputDir(tsConfigPath, workspaceRoot) {
42
- const fullPath = path.resolve(workspaceRoot, tsConfigPath);
43
- const configContent = await fs.readFile(fullPath, 'utf-8');
44
- const config = JSON.parse(configContent);
45
-
46
- const outDir = config.compilerOptions?.outDir || 'dist';
47
- const tsConfigDir = path.dirname(fullPath);
48
-
49
- return path.resolve(tsConfigDir, outDir);
50
- }
51
-
52
- async function compileTypeScript(tsConfig, context) {
53
- await execa('tsc', ['-p', tsConfig], {
54
- stdio: 'inherit',
55
- cwd: context.currentDirectory,
56
- });
57
- }
58
-
59
- async function copyProjectFiles(files, outputDir, context) {
60
- await cpy(files, outputDir, {
61
- parents: true,
62
- cwd: context.currentDirectory,
63
- });
64
- }
65
-
66
- async function cleanPackageJson(outputDir) {
67
- const distPackageJson = path.join(outputDir, 'package.json');
68
- const pkg = await fs.readJson(distPackageJson);
69
- delete pkg.scripts;
70
- delete pkg.devDependencies;
71
- await fs.writeJson(distPackageJson, pkg, { spaces: 2 });
72
- }
73
-
74
- export default createBuilder(async (options, context) => {
75
- try {
76
- const outputDir = await getOutputDir(options.tsConfig, context.workspaceRoot);
77
- LOG.info(context.logger, 'BUILD', 'Starting build process...');
78
-
79
- LOG.info(context.logger, 'CLEANING', `Cleaning old distribution files in ${outputDir}`);
80
- await cleanOutputDirectory(outputDir, context);
81
- LOG.info(context.logger, 'CLEANING', `Cleaning completed successfully.`);
82
-
83
- LOG.info(context.logger, 'COMPILING', `Compiling TypeScript files using config: ${options.tsConfig}`);
84
- await compileTypeScript(options.tsConfig, context);
85
- LOG.info(context.logger, 'COMPILING', 'Compilation completed successfully.');
86
-
87
- LOG.info(context.logger, 'COPYING', `Copying project files to: ${outputDir}`);
88
- await copyProjectFiles(options.files, outputDir, context);
89
- LOG.info(context.logger, 'COPYING', 'Copy completed successfully.');
90
-
91
- LOG.info(context.logger, 'UPDATING', `Updating package.json file.`);
92
- await cleanPackageJson(outputDir);
93
- LOG.info(context.logger, 'UPDATING', 'Update completed successfully.');
94
-
95
- return { success: true };
96
- } catch (error) {
97
- LOG.error(context.logger, 'ERROR', `Build failed: ${error.message}`);
98
- return { success: false };
99
- }
100
- });
@@ -1,18 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/schema",
3
- "type": "object",
4
- "properties": {
5
- "files": {
6
- "type": "array",
7
- "items": {
8
- "type": "string"
9
- }
10
- },
11
- "outputDir": {
12
- "type": "string"
13
- },
14
- "tsConfig": {
15
- "type": "string"
16
- }
17
- }
18
- }
@@ -1,11 +0,0 @@
1
- {
2
- "name": "schematic-builder",
3
- "version": "1.0.0",
4
- "scripts": {
5
- "test": "echo \"Error: no test specified\" && exit 1"
6
- },
7
- "author": "",
8
- "license": "ISC",
9
- "description": "",
10
- "builders": "./builders/builders.json"
11
- }
@@ -1,50 +0,0 @@
1
- import { SchematicsException, Tree } from '@angular-devkit/schematics';
2
-
3
- export function addPathToTsconfigUtil(tree: Tree, key: string, value: string[]): void {
4
- const tsconfigPath = 'tsconfig.json';
5
-
6
- // Check if tsconfig.json exists
7
- if (!tree.exists(tsconfigPath)) {
8
- throw new SchematicsException('tsconfig.json does not exist');
9
- }
10
-
11
- // Read tsconfig.json content as string
12
- const tsconfigBuffer = tree.read(tsconfigPath);
13
- if (!tsconfigBuffer) {
14
- throw new SchematicsException('Failed to read tsconfig.json');
15
- }
16
- let tsconfigContent = tsconfigBuffer.toString('utf-8');
17
-
18
- // Extract and preserve the comment
19
- const commentMatch = tsconfigContent.match(/\/\*[\s\S]*?\*\//);
20
- const comment = commentMatch ? commentMatch[0] : '';
21
-
22
- // Remove comment from content to parse JSON
23
- tsconfigContent = tsconfigContent.replace(comment, '');
24
-
25
- // Parse tsconfig.json content
26
- let tsconfig;
27
- try {
28
- tsconfig = JSON.parse(tsconfigContent);
29
- } catch (e) {
30
- throw new SchematicsException('Failed to parse tsconfig.json' + e);
31
- }
32
-
33
- // Modify compilerOptions.paths to add your new mapping
34
- if (!tsconfig.compilerOptions) {
35
- tsconfig.compilerOptions = {};
36
- }
37
- if (!tsconfig.compilerOptions.paths) {
38
- tsconfig.compilerOptions.paths = {};
39
- }
40
- tsconfig.compilerOptions.paths[key] = value;
41
-
42
- // Convert tsconfig back to JSON string
43
- tsconfigContent = JSON.stringify(tsconfig, null, 2);
44
-
45
- // Ensure the preserved comment is prepended to the JSON string
46
- tsconfigContent = `${comment}\n${tsconfigContent}`;
47
-
48
- // Write back to tsconfig.json
49
- tree.overwrite(tsconfigPath, tsconfigContent);
50
- }