@ng-zen/cli 22.4.1-next.1 → 22.5.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 (47) hide show
  1. package/README.md +37 -3
  2. package/eslint-config/index.js +130 -0
  3. package/package.json +14 -1
  4. package/schematics/ng-add/eslint-config.js +87 -0
  5. package/schematics/ng-add/eslint-config.js.map +1 -0
  6. package/schematics/ng-add/eslint-config.ts +98 -0
  7. package/schematics/ng-add/icon-library/icon-library.js +2 -1
  8. package/schematics/ng-add/icon-library/icon-library.js.map +1 -1
  9. package/schematics/ng-add/icon-library/icon-library.ts +2 -1
  10. package/schematics/ng-add/index.js +14 -2
  11. package/schematics/ng-add/index.js.map +1 -1
  12. package/schematics/ng-add/index.ts +14 -3
  13. package/schematics/ng-add/schema.js.map +1 -1
  14. package/schematics/ng-add/schema.json +5 -0
  15. package/schematics/ng-add/schema.ts +1 -0
  16. package/schematics/ui/files/avatar/avatar.ts +1 -1
  17. package/schematics/ui/files/checkbox/checkbox.stories.ts +1 -1
  18. package/schematics/ui/files/checkbox/checkbox.ts +2 -2
  19. package/schematics/ui/files/dialog/dialog.service.stories.ts +3 -3
  20. package/schematics/ui/files/dialog/dialog.service.ts +2 -2
  21. package/schematics/ui/files/dialog/dialog.spec.ts +6 -6
  22. package/schematics/ui/files/dialog/dialog.ts +1 -1
  23. package/schematics/ui/files/form-control/form-control.ts +5 -5
  24. package/schematics/ui/files/icon/icon.ts +5 -5
  25. package/schematics/ui/files/input/input.stories.ts +4 -4
  26. package/schematics/ui/files/input/input.ts +1 -1
  27. package/schematics/ui/files/pin/index.ts +3 -0
  28. package/schematics/ui/files/pin/pin-item.spec.ts +151 -0
  29. package/schematics/ui/files/pin/pin-item.ts +115 -0
  30. package/schematics/ui/files/pin/pin.spec.ts +153 -0
  31. package/schematics/ui/files/pin/pin.stories.ts +164 -0
  32. package/schematics/ui/files/pin/pin.ts +49 -0
  33. package/schematics/ui/files/pin/pin.types.ts +15 -0
  34. package/schematics/ui/files/popover/popover.spec.ts +10 -7
  35. package/schematics/ui/files/popover/popover.stories.ts +1 -1
  36. package/schematics/ui/files/radio/radio.stories.ts +3 -3
  37. package/schematics/ui/files/radio/radio.ts +3 -3
  38. package/schematics/ui/files/switch/switch.stories.ts +1 -1
  39. package/schematics/ui/index.js +2 -4
  40. package/schematics/ui/index.js.map +1 -1
  41. package/schematics/ui/index.ts +2 -4
  42. package/schematics/ui/schema.js.map +1 -1
  43. package/schematics/ui/schema.json +1 -0
  44. package/schematics/ui/schema.ts +1 -0
  45. package/utils/apply-file-template.util.js.map +1 -1
  46. package/utils/apply-file-template.util.ts +3 -3
  47. package/CHANGELOG.md +0 -8
package/README.md CHANGED
@@ -81,9 +81,10 @@ export class MyComponent {}
81
81
  3. [CLI Usage & Options](#-cli-usage--options)
82
82
  4. [Available UIs](#-available-uis)
83
83
  5. [Customization](#-customization)
84
- 6. [Philosophy & Architecture](#-philosophy--architecture)
85
- 7. [Community & Contributions](#-community--contributions)
86
- 8. [Documentation & Links](#-documentation--links)
84
+ 6. [ESLint Configuration](#-eslint-configuration)
85
+ 7. [Philosophy & Architecture](#-philosophy--architecture)
86
+ 8. [Community & Contributions](#-community--contributions)
87
+ 9. [Documentation & Links](#-documentation--links)
87
88
 
88
89
  ## ✨ Features
89
90
 
@@ -166,6 +167,7 @@ ng generate @ng-zen/cli:ui --ui button input --stories
166
167
  | ----------- | ---------------------------- | ------------------------------------------------------------------------- |
167
168
  | **Button** | Interactive buttons | Primary/secondary variants, loading states, icons |
168
169
  | **Dialog** | Native modal dialogs | Native dialog element, service API, size variants, backdrop config |
170
+ | **Pin** | Anchor-positioned overlay | CSS Anchor Positioning, TemplateRef content, position and offset controls |
169
171
  | **Popover** | Native Popover API directive | Template/string content, placements, click toggle, CSS anchor positioning |
170
172
 
171
173
  ## 🎨 Customization
@@ -188,6 +190,38 @@ Every generated component utilizes CSS variables for immediate theming without t
188
190
 
189
191
  For structural changes (e.g., modifying the default `0.625rem` border radius or internal padding), simply edit the generated `.scss` files in your `./ui` directory.
190
192
 
193
+ ## 🔧 ESLint Configuration
194
+
195
+ ng-zen provides a flat ESLint config for UI components and generated files.
196
+
197
+ **Auto-setup** during `ng add`:
198
+
199
+ ```bash
200
+ ng add @ng-zen/cli
201
+ # → Prompt: "ESLint config detected. Update it for ng-zen UI components?"
202
+ ```
203
+
204
+ It adds `@ng-zen/cli/eslint-config` to your `eslint.config.*` and spreads it into the `defineConfig` array. This enforces the `zen` prefix on component selectors and relaxes rules for `.stories.ts` / `.spec.ts` files generated inside `ui/` directories.
205
+
206
+ **Manual setup** (if you declined the prompt):
207
+
208
+ ```ts
209
+ import ngZen from '@ng-zen/cli/eslint-config';
210
+
211
+ export default defineConfig([...otherConfigs, ...ngZen]);
212
+ ```
213
+
214
+ **Custom path or rules** — use the named exports for fine-grained control:
215
+
216
+ ```ts
217
+ import ngZen from '@ng-zen/cli/eslint-config';
218
+
219
+ export default defineConfig([
220
+ ngZen.createNgZenConfig({ uiFiles: 'src/app/shared/components' }),
221
+ ...ngZen.generatedFiles,
222
+ ]);
223
+ ```
224
+
191
225
  ## 🏛️ Philosophy & Architecture
192
226
 
193
227
  ### Perfect For
@@ -0,0 +1,130 @@
1
+ // @ts-check
2
+ const { defineConfig } = require('eslint/config');
3
+
4
+ /**
5
+ * Config block for UI components inside a `ui/` directory.
6
+ *
7
+ * Enforces:
8
+ * - `zen` prefix for component selectors (`element`, `kebab-case`)
9
+ * - `zen` prefix for directive selectors (`attribute`, `camelCase`)
10
+ * - At most 2 classes per file
11
+ *
12
+ * @type {import('eslint').Linter.Config}
13
+ */
14
+ const uiComponent = {
15
+ files: ['**/ui/**/*.ts'],
16
+ rules: {
17
+ '@angular-eslint/directive-selector': ['error', { type: 'attribute', prefix: 'zen', style: 'camelCase' }],
18
+ '@angular-eslint/component-selector': ['error', { type: 'element', prefix: 'zen', style: 'kebab-case' }],
19
+ 'max-classes-per-file': ['error', 2],
20
+ },
21
+ };
22
+
23
+ /**
24
+ * Config block for generated files — specs, tests, and Storybook stories.
25
+ *
26
+ * Relaxes strict rules that are impractical for test/story files:
27
+ * disables `explicit-function-return-type`, `no-unsafe-*`, `max-classes-per-file`,
28
+ * `no-empty-function`, `require-await`, `unbound-method`, and `no-floating-promises`.
29
+ *
30
+ * @type {import('eslint').Linter.Config}
31
+ */
32
+ const generatedFiles = {
33
+ files: ['**/ui/**/*.spec.ts', '**/ui/**/*.test.ts', '**/ui/**/*.stories.ts'],
34
+ rules: {
35
+ '@typescript-eslint/unbound-method': 'off',
36
+ '@typescript-eslint/no-unsafe-return': 'off',
37
+ '@typescript-eslint/no-unsafe-call': 'off',
38
+ '@typescript-eslint/no-unsafe-member-access': 'off',
39
+ '@typescript-eslint/no-unsafe-assignment': 'off',
40
+ '@typescript-eslint/no-floating-promises': 'off',
41
+ '@typescript-eslint/no-empty-function': 'off',
42
+ '@typescript-eslint/explicit-function-return-type': 'off',
43
+ '@typescript-eslint/require-await': 'off',
44
+ 'max-classes-per-file': 'off',
45
+ },
46
+ };
47
+
48
+ /**
49
+ * Creates a custom UI component config block with a custom file glob.
50
+ *
51
+ * @param {Object} [options]
52
+ * @param {string | string[]} [options.uiFiles] - Glob pattern(s) for UI component files.
53
+ * Uses the same format as the `files` property in flat config.
54
+ * @returns {import('eslint').Linter.Config} A config block with the same rules as
55
+ * uiComponent but scoped to the provided file pattern.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * createNgZenConfig({ uiFiles: 'libs/my-ui' })
60
+ * ```
61
+ */
62
+ function createNgZenConfig(options = {}) {
63
+ const { uiFiles = ['**/ui/**/*.ts'] } = options;
64
+ return { ...uiComponent, files: [uiFiles].flat() };
65
+ }
66
+
67
+ /**
68
+ * ng-zen ESLint flat config.
69
+ *
70
+ * ## Default import
71
+ *
72
+ * Import the whole array of flat configs:
73
+ * ```ts
74
+ * import ngZen from '@ng-zen/cli/eslint-config';
75
+ * export default defineConfig([...ngZen]);
76
+ * ```
77
+ *
78
+ * ## Named properties
79
+ *
80
+ * | Property | Returns | Description |
81
+ * |---|---|---|
82
+ * | `.uiComponent` | `Config` | Rules for UI component files. Override `files` / `rules` via spread. |
83
+ * | `.generatedFiles` | `Config` | Rules for generated files (stories, spec, test). |
84
+ * | `.createNgZenConfig(opts)` | `Config` | Helper — same rules as uiComponent with a custom file glob. |
85
+ *
86
+ * ## Custom path
87
+ *
88
+ * By default, UI component files are detected via a glob pattern targeting any `ui` directory
89
+ * (glob: `**` + `/ui/` + `**` + `/*`). If your components live in a different location, choose one of the
90
+ * approaches below instead of the default `...ngZen` spread.
91
+ *
92
+ * @example <caption>Custom UI path</caption>
93
+ * ```ts
94
+ * import ngZen from '@ng-zen/cli/eslint-config';
95
+ * export default defineConfig([
96
+ * ngZen.createNgZenConfig({ uiFiles: 'src/app/shared/ui' }),
97
+ * ...ngZen.generatedFiles,
98
+ * ]);
99
+ * ```
100
+ *
101
+ * @example <caption>Override prefix or rules</caption>
102
+ * ```ts
103
+ * import ngZen from '@ng-zen/cli/eslint-config';
104
+ * export default defineConfig([
105
+ * {
106
+ * files: ['libs/my-ui'],
107
+ * rules: {
108
+ * ...ngZen.uiComponent.rules,
109
+ * '@angular-eslint/component-selector': ['error', { type: 'element', prefix: ['app', 'zen'], style: 'kebab-case' }],
110
+ * },
111
+ * },
112
+ * ...ngZen.generatedFiles,
113
+ * ]);
114
+ * ```
115
+ *
116
+ * @type {import('eslint').Linter.FlatConfig[] &
117
+ * {
118
+ * uiComponent: import('eslint').Linter.Config,
119
+ * generatedFiles: import('eslint').Linter.Config,
120
+ * createNgZenConfig: (options?: { uiFiles?: string | string[] }) => import('eslint').Linter.Config
121
+ * }
122
+ * }
123
+ */
124
+ const config = Object.assign(defineConfig([uiComponent, generatedFiles]), {
125
+ uiComponent,
126
+ generatedFiles,
127
+ createNgZenConfig,
128
+ });
129
+
130
+ module.exports = config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-zen/cli",
3
- "version": "22.4.1-next.1",
3
+ "version": "22.5.0-next.1",
4
4
  "description": "Angular CLI generator for creating fully customizable UI components.",
5
5
  "license": "BSD-2-Clause",
6
6
  "private": false,
@@ -59,6 +59,7 @@
59
59
  "form-control",
60
60
  "icon",
61
61
  "input",
62
+ "pin",
62
63
  "popover",
63
64
  "radio",
64
65
  "skeleton",
@@ -68,8 +69,20 @@
68
69
  "ng-add": {
69
70
  "save": "devDependencies"
70
71
  },
72
+ "exports": {
73
+ "./eslint-config": "./eslint-config/index.js",
74
+ "./package.json": "./package.json"
75
+ },
71
76
  "schematics": "./schematics/collection.json",
72
77
  "packageManager": "pnpm@10.24.0",
78
+ "pnpm": {
79
+ "peerDependencyRules": {
80
+ "allowedVersions": {
81
+ "typescript": "6",
82
+ "chokidar": "5"
83
+ }
84
+ }
85
+ },
73
86
  "dependencies": {
74
87
  "@angular-devkit/core": "^22.0.1",
75
88
  "@angular-devkit/schematics": "^22.0.1",
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findEslintConfig = findEslintConfig;
4
+ exports.logEslintManualInstructions = logEslintManualInstructions;
5
+ exports.updateEslintConfig = updateEslintConfig;
6
+ function findEslintConfig(tree) {
7
+ for (const name of ['eslint.config.js', 'eslint.config.mjs', 'eslint.config.ts']) {
8
+ if (tree.exists(name))
9
+ return name;
10
+ }
11
+ return null;
12
+ }
13
+ function detectFormat(code) {
14
+ return code.includes('require(') || code.includes('module.exports') ? 'cjs' : 'esm';
15
+ }
16
+ function getImportStatement(code) {
17
+ if (detectFormat(code) === 'cjs') {
18
+ return "const ngZen = require('@ng-zen/cli/eslint-config');\n";
19
+ }
20
+ return "import ngZen from '@ng-zen/cli/eslint-config';\n";
21
+ }
22
+ function addImport(code) {
23
+ if (code.includes('@ng-zen/cli/eslint-config'))
24
+ return code;
25
+ const statement = getImportStatement(code);
26
+ if (detectFormat(code) === 'cjs') {
27
+ const lastRequire = code.lastIndexOf('\nconst ');
28
+ if (lastRequire < 0)
29
+ return code;
30
+ const insertAt = code.indexOf('\n', lastRequire + 1) + 1;
31
+ return code.slice(0, insertAt) + statement + code.slice(insertAt);
32
+ }
33
+ const importEnd = code.lastIndexOf('\nimport ');
34
+ const insertAt = importEnd > 0 ? code.indexOf('\n', importEnd + 1) + 1 : code.indexOf('\n') + 1;
35
+ return code.slice(0, insertAt) + statement + code.slice(insertAt);
36
+ }
37
+ function spreadConfig(code) {
38
+ const defineConfigMatch = /defineConfig\(\s*\[([\s\S]*?)\]\s*\)/.exec(code);
39
+ if (!defineConfigMatch)
40
+ return code;
41
+ const existingArray = defineConfigMatch[0];
42
+ if (existingArray.includes('...ngZen'))
43
+ return code;
44
+ const newArray = existingArray.replace(/\]\s*\)$/, ', ...ngZen,\n ])');
45
+ return code.replace(existingArray, newArray);
46
+ }
47
+ function logEslintManualInstructions() {
48
+ return (tree, context) => {
49
+ const configPath = findEslintConfig(tree);
50
+ if (!configPath)
51
+ return tree;
52
+ context.logger.info('');
53
+ context.logger.info('⚠️ To add ng-zen ESLint config manually:');
54
+ context.logger.info(' 1. Run: npm install -D @ng-zen/cli');
55
+ context.logger.info(' 2. In eslint.config.js, add:');
56
+ context.logger.info(" import ngZen from '@ng-zen/cli/eslint-config';");
57
+ context.logger.info(' // then spread ...ngZen into the defineConfig array');
58
+ context.logger.info(' See: Manual Configuration page in Storybook');
59
+ return tree;
60
+ };
61
+ }
62
+ function updateEslintConfig() {
63
+ return (tree, context) => {
64
+ const configPath = findEslintConfig(tree);
65
+ if (!configPath) {
66
+ context.logger.info('ℹ️ No flat ESLint config found — skip ESLint update');
67
+ return tree;
68
+ }
69
+ let code = tree.read(configPath).toString('utf-8');
70
+ if (!code.includes('defineConfig')) {
71
+ context.logger.warn('⚠️ ESLint config does not use defineConfig — skip automatic update');
72
+ return tree;
73
+ }
74
+ const hadImport = code.includes('@ng-zen/cli/eslint-config');
75
+ code = addImport(code);
76
+ code = spreadConfig(code);
77
+ tree.overwrite(configPath, code);
78
+ if (hadImport) {
79
+ context.logger.info('✅ ESLint config already has @ng-zen/cli config — ensured it is in defineConfig array');
80
+ }
81
+ else {
82
+ context.logger.info('✅ Added @ng-zen/cli/eslint-config to ESLint config');
83
+ }
84
+ return tree;
85
+ };
86
+ }
87
+ //# sourceMappingURL=eslint-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint-config.js","sourceRoot":"","sources":["../../../../../src/schematics/ng-add/eslint-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\n\ntype ModuleFormat = 'cjs' | 'esm';\n\nexport function findEslintConfig(tree: Tree): string | null {\n for (const name of ['eslint.config.js', 'eslint.config.mjs', 'eslint.config.ts']) {\n if (tree.exists(name)) return name;\n }\n return null;\n}\n\nfunction detectFormat(code: string): ModuleFormat {\n return code.includes('require(') || code.includes('module.exports') ? 'cjs' : 'esm';\n}\n\nfunction getImportStatement(code: string): string {\n if (detectFormat(code) === 'cjs') {\n return \"const ngZen = require('@ng-zen/cli/eslint-config');\\n\";\n }\n return \"import ngZen from '@ng-zen/cli/eslint-config';\\n\";\n}\n\nfunction addImport(code: string): string {\n if (code.includes('@ng-zen/cli/eslint-config')) return code;\n\n const statement = getImportStatement(code);\n\n if (detectFormat(code) === 'cjs') {\n const lastRequire = code.lastIndexOf('\\nconst ');\n if (lastRequire < 0) return code;\n const insertAt = code.indexOf('\\n', lastRequire + 1) + 1;\n return code.slice(0, insertAt) + statement + code.slice(insertAt);\n }\n\n const importEnd = code.lastIndexOf('\\nimport ');\n const insertAt = importEnd > 0 ? code.indexOf('\\n', importEnd + 1) + 1 : code.indexOf('\\n') + 1;\n return code.slice(0, insertAt) + statement + code.slice(insertAt);\n}\n\nfunction spreadConfig(code: string): string {\n const defineConfigMatch = /defineConfig\\(\\s*\\[([\\s\\S]*?)\\]\\s*\\)/.exec(code);\n if (!defineConfigMatch) return code;\n\n const existingArray = defineConfigMatch[0];\n if (existingArray.includes('...ngZen')) return code;\n\n const newArray = existingArray.replace(/\\]\\s*\\)$/, ', ...ngZen,\\n ])');\n return code.replace(existingArray, newArray);\n}\n\nexport function logEslintManualInstructions(): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const configPath = findEslintConfig(tree);\n if (!configPath) return tree;\n\n context.logger.info('');\n context.logger.info('⚠️ To add ng-zen ESLint config manually:');\n context.logger.info(' 1. Run: npm install -D @ng-zen/cli');\n context.logger.info(' 2. In eslint.config.js, add:');\n context.logger.info(\" import ngZen from '@ng-zen/cli/eslint-config';\");\n context.logger.info(' // then spread ...ngZen into the defineConfig array');\n context.logger.info(' See: Manual Configuration page in Storybook');\n\n return tree;\n };\n}\n\nexport function updateEslintConfig(): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const configPath = findEslintConfig(tree);\n\n if (!configPath) {\n context.logger.info('ℹ️ No flat ESLint config found — skip ESLint update');\n return tree;\n }\n\n let code = tree.read(configPath)!.toString('utf-8');\n\n if (!code.includes('defineConfig')) {\n context.logger.warn('⚠️ ESLint config does not use defineConfig — skip automatic update');\n return tree;\n }\n\n const hadImport = code.includes('@ng-zen/cli/eslint-config');\n code = addImport(code);\n code = spreadConfig(code);\n\n tree.overwrite(configPath, code);\n\n if (hadImport) {\n context.logger.info('✅ ESLint config already has @ng-zen/cli config — ensured it is in defineConfig array');\n } else {\n context.logger.info('✅ Added @ng-zen/cli/eslint-config to ESLint config');\n }\n\n return tree;\n };\n}\n"]}
@@ -0,0 +1,98 @@
1
+ import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
2
+
3
+ type ModuleFormat = 'cjs' | 'esm';
4
+
5
+ export function findEslintConfig(tree: Tree): string | null {
6
+ for (const name of ['eslint.config.js', 'eslint.config.mjs', 'eslint.config.ts']) {
7
+ if (tree.exists(name)) return name;
8
+ }
9
+ return null;
10
+ }
11
+
12
+ function detectFormat(code: string): ModuleFormat {
13
+ return code.includes('require(') || code.includes('module.exports') ? 'cjs' : 'esm';
14
+ }
15
+
16
+ function getImportStatement(code: string): string {
17
+ if (detectFormat(code) === 'cjs') {
18
+ return "const ngZen = require('@ng-zen/cli/eslint-config');\n";
19
+ }
20
+ return "import ngZen from '@ng-zen/cli/eslint-config';\n";
21
+ }
22
+
23
+ function addImport(code: string): string {
24
+ if (code.includes('@ng-zen/cli/eslint-config')) return code;
25
+
26
+ const statement = getImportStatement(code);
27
+
28
+ if (detectFormat(code) === 'cjs') {
29
+ const lastRequire = code.lastIndexOf('\nconst ');
30
+ if (lastRequire < 0) return code;
31
+ const insertAt = code.indexOf('\n', lastRequire + 1) + 1;
32
+ return code.slice(0, insertAt) + statement + code.slice(insertAt);
33
+ }
34
+
35
+ const importEnd = code.lastIndexOf('\nimport ');
36
+ const insertAt = importEnd > 0 ? code.indexOf('\n', importEnd + 1) + 1 : code.indexOf('\n') + 1;
37
+ return code.slice(0, insertAt) + statement + code.slice(insertAt);
38
+ }
39
+
40
+ function spreadConfig(code: string): string {
41
+ const defineConfigMatch = /defineConfig\(\s*\[([\s\S]*?)\]\s*\)/.exec(code);
42
+ if (!defineConfigMatch) return code;
43
+
44
+ const existingArray = defineConfigMatch[0];
45
+ if (existingArray.includes('...ngZen')) return code;
46
+
47
+ const newArray = existingArray.replace(/\]\s*\)$/, ', ...ngZen,\n ])');
48
+ return code.replace(existingArray, newArray);
49
+ }
50
+
51
+ export function logEslintManualInstructions(): Rule {
52
+ return (tree: Tree, context: SchematicContext) => {
53
+ const configPath = findEslintConfig(tree);
54
+ if (!configPath) return tree;
55
+
56
+ context.logger.info('');
57
+ context.logger.info('⚠️ To add ng-zen ESLint config manually:');
58
+ context.logger.info(' 1. Run: npm install -D @ng-zen/cli');
59
+ context.logger.info(' 2. In eslint.config.js, add:');
60
+ context.logger.info(" import ngZen from '@ng-zen/cli/eslint-config';");
61
+ context.logger.info(' // then spread ...ngZen into the defineConfig array');
62
+ context.logger.info(' See: Manual Configuration page in Storybook');
63
+
64
+ return tree;
65
+ };
66
+ }
67
+
68
+ export function updateEslintConfig(): Rule {
69
+ return (tree: Tree, context: SchematicContext) => {
70
+ const configPath = findEslintConfig(tree);
71
+
72
+ if (!configPath) {
73
+ context.logger.info('ℹ️ No flat ESLint config found — skip ESLint update');
74
+ return tree;
75
+ }
76
+
77
+ let code = tree.read(configPath)!.toString('utf-8');
78
+
79
+ if (!code.includes('defineConfig')) {
80
+ context.logger.warn('⚠️ ESLint config does not use defineConfig — skip automatic update');
81
+ return tree;
82
+ }
83
+
84
+ const hadImport = code.includes('@ng-zen/cli/eslint-config');
85
+ code = addImport(code);
86
+ code = spreadConfig(code);
87
+
88
+ tree.overwrite(configPath, code);
89
+
90
+ if (hadImport) {
91
+ context.logger.info('✅ ESLint config already has @ng-zen/cli config — ensured it is in defineConfig array');
92
+ } else {
93
+ context.logger.info('✅ Added @ng-zen/cli/eslint-config to ESLint config');
94
+ }
95
+
96
+ return tree;
97
+ };
98
+ }
@@ -16,7 +16,8 @@ function installIconLibrary() {
16
16
  }
17
17
  function logIconLibraryManualInstructions() {
18
18
  return (tree, context) => {
19
- context.logger.info('To use <zen-icon>, install an SVG icon library (one-time setup):');
19
+ context.logger.info('');
20
+ context.logger.info('⚠️ To use <zen-icon>, install an SVG icon library (one-time setup):');
20
21
  context.logger.info(' - Recommended: @hugeicons/core-free-icons');
21
22
  context.logger.info(' - Or use any other SVG icon library and pass icons via the [icon] input.');
22
23
  return tree;
@@ -1 +1 @@
1
- {"version":3,"file":"icon-library.js","sourceRoot":"","sources":["../../../../../../src/schematics/ng-add/icon-library/icon-library.ts"],"names":[],"mappings":";;AAMA,gDAWC;AAED,4EAQC;AA1BD,4DAA0E;AAC1E,2EAAoF;AAEpF,qDAAqD;AAErD,SAAgB,kBAAkB;IAChC,OAAO,CAAC,IAAU,EAAE,OAAyB,EAAE,EAAE;QAC/C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QAEnE,IAAA,uCAAwB,EAAC,IAAI,EAAE,kCAAiB,CAAC,CAAC;QAClD,OAAO,CAAC,OAAO,CAAC,IAAI,8BAAsB,EAAE,CAAC,CAAC;QAE9C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;QAEpF,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,gCAAgC;IAC9C,OAAO,CAAC,IAAU,EAAE,OAAyB,EAAE,EAAE;QAC/C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;QACxF,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QACnE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAC;QAElG,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';\nimport { addPackageJsonDependency } from '@schematics/angular/utility/dependencies';\n\nimport { HugeiconsCoreFree } from './icon-libraries';\n\nexport function installIconLibrary(): Rule {\n return (tree: Tree, context: SchematicContext) => {\n context.logger.info('📦 Installing @hugeicons/core-free-icons...');\n\n addPackageJsonDependency(tree, HugeiconsCoreFree);\n context.addTask(new NodePackageInstallTask());\n\n context.logger.info('✅ @hugeicons/core-free-icons has been added to your project.');\n\n return tree;\n };\n}\n\nexport function logIconLibraryManualInstructions(): Rule {\n return (tree: Tree, context: SchematicContext) => {\n context.logger.info('To use <zen-icon>, install an SVG icon library (one-time setup):');\n context.logger.info(' - Recommended: @hugeicons/core-free-icons');\n context.logger.info(' - Or use any other SVG icon library and pass icons via the [icon] input.');\n\n return tree;\n };\n}\n"]}
1
+ {"version":3,"file":"icon-library.js","sourceRoot":"","sources":["../../../../../../src/schematics/ng-add/icon-library/icon-library.ts"],"names":[],"mappings":";;AAMA,gDAWC;AAED,4EASC;AA3BD,4DAA0E;AAC1E,2EAAoF;AAEpF,qDAAqD;AAErD,SAAgB,kBAAkB;IAChC,OAAO,CAAC,IAAU,EAAE,OAAyB,EAAE,EAAE;QAC/C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QAEnE,IAAA,uCAAwB,EAAC,IAAI,EAAE,kCAAiB,CAAC,CAAC;QAClD,OAAO,CAAC,OAAO,CAAC,IAAI,8BAAsB,EAAE,CAAC,CAAC;QAE9C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;QAEpF,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,gCAAgC;IAC9C,OAAO,CAAC,IAAU,EAAE,OAAyB,EAAE,EAAE;QAC/C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;QAC3F,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QACnE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAC;QAElG,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';\nimport { addPackageJsonDependency } from '@schematics/angular/utility/dependencies';\n\nimport { HugeiconsCoreFree } from './icon-libraries';\n\nexport function installIconLibrary(): Rule {\n return (tree: Tree, context: SchematicContext) => {\n context.logger.info('📦 Installing @hugeicons/core-free-icons...');\n\n addPackageJsonDependency(tree, HugeiconsCoreFree);\n context.addTask(new NodePackageInstallTask());\n\n context.logger.info('✅ @hugeicons/core-free-icons has been added to your project.');\n\n return tree;\n };\n}\n\nexport function logIconLibraryManualInstructions(): Rule {\n return (tree: Tree, context: SchematicContext) => {\n context.logger.info('');\n context.logger.info('⚠️ To use <zen-icon>, install an SVG icon library (one-time setup):');\n context.logger.info(' - Recommended: @hugeicons/core-free-icons');\n context.logger.info(' - Or use any other SVG icon library and pass icons via the [icon] input.');\n\n return tree;\n };\n}\n"]}
@@ -19,7 +19,8 @@ export function installIconLibrary(): Rule {
19
19
 
20
20
  export function logIconLibraryManualInstructions(): Rule {
21
21
  return (tree: Tree, context: SchematicContext) => {
22
- context.logger.info('To use <zen-icon>, install an SVG icon library (one-time setup):');
22
+ context.logger.info('');
23
+ context.logger.info('⚠️ To use <zen-icon>, install an SVG icon library (one-time setup):');
23
24
  context.logger.info(' - Recommended: @hugeicons/core-free-icons');
24
25
  context.logger.info(' - Or use any other SVG icon library and pass icons via the [icon] input.');
25
26
 
@@ -1,14 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ngAdd = ngAdd;
4
+ const schematics_1 = require("@angular-devkit/schematics");
5
+ const eslint_config_1 = require("./eslint-config");
4
6
  const icon_library_1 = require("./icon-library");
5
7
  function ngAdd(options) {
6
8
  return (tree, context) => {
7
9
  context.logger.info('🔧 Setting up ng-zen...');
10
+ const rules = [];
8
11
  if (options.installIconLibrary) {
9
- return (0, icon_library_1.installIconLibrary)()(tree, context);
12
+ rules.push((0, icon_library_1.installIconLibrary)());
10
13
  }
11
- return (0, icon_library_1.logIconLibraryManualInstructions)()(tree, context);
14
+ else {
15
+ rules.push((0, icon_library_1.logIconLibraryManualInstructions)());
16
+ }
17
+ if (options.updateEslint) {
18
+ rules.push((0, eslint_config_1.updateEslintConfig)());
19
+ }
20
+ else {
21
+ rules.push((0, eslint_config_1.logEslintManualInstructions)());
22
+ }
23
+ return (0, schematics_1.chain)(rules)(tree, context);
12
24
  };
13
25
  }
14
26
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/schematics/ng-add/index.ts"],"names":[],"mappings":";;AAKA,sBAUC;AAbD,iDAAsF;AAGtF,SAAgB,KAAK,CAAC,OAAe;IACnC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE;QACvB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAE/C,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;YAC/B,OAAO,IAAA,iCAAkB,GAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO,IAAA,+CAAgC,GAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3D,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { Rule } from '@angular-devkit/schematics';\n\nimport { installIconLibrary, logIconLibraryManualInstructions } from './icon-library';\nimport { Schema } from './schema';\n\nexport function ngAdd(options: Schema): Rule {\n return (tree, context) => {\n context.logger.info('🔧 Setting up ng-zen...');\n\n if (options.installIconLibrary) {\n return installIconLibrary()(tree, context);\n }\n\n return logIconLibraryManualInstructions()(tree, context);\n };\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/schematics/ng-add/index.ts"],"names":[],"mappings":";;AAMA,sBAoBC;AA1BD,2DAAyD;AAEzD,mDAAkF;AAClF,iDAAsF;AAGtF,SAAgB,KAAK,CAAC,OAAe;IACnC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE;QACvB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAE/C,MAAM,KAAK,GAAW,EAAE,CAAC;QAEzB,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,IAAA,iCAAkB,GAAE,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,IAAA,+CAAgC,GAAE,CAAC,CAAC;QACjD,CAAC;QAED,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,IAAA,kCAAkB,GAAE,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,IAAA,2CAA2B,GAAE,CAAC,CAAC;QAC5C,CAAC;QAED,OAAO,IAAA,kBAAK,EAAC,KAAK,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { chain, Rule } from '@angular-devkit/schematics';\n\nimport { logEslintManualInstructions, updateEslintConfig } from './eslint-config';\nimport { installIconLibrary, logIconLibraryManualInstructions } from './icon-library';\nimport { Schema } from './schema';\n\nexport function ngAdd(options: Schema): Rule {\n return (tree, context) => {\n context.logger.info('🔧 Setting up ng-zen...');\n\n const rules: Rule[] = [];\n\n if (options.installIconLibrary) {\n rules.push(installIconLibrary());\n } else {\n rules.push(logIconLibraryManualInstructions());\n }\n\n if (options.updateEslint) {\n rules.push(updateEslintConfig());\n } else {\n rules.push(logEslintManualInstructions());\n }\n\n return chain(rules)(tree, context);\n };\n}\n"]}
@@ -1,5 +1,6 @@
1
- import { Rule } from '@angular-devkit/schematics';
1
+ import { chain, Rule } from '@angular-devkit/schematics';
2
2
 
3
+ import { logEslintManualInstructions, updateEslintConfig } from './eslint-config';
3
4
  import { installIconLibrary, logIconLibraryManualInstructions } from './icon-library';
4
5
  import { Schema } from './schema';
5
6
 
@@ -7,10 +8,20 @@ export function ngAdd(options: Schema): Rule {
7
8
  return (tree, context) => {
8
9
  context.logger.info('🔧 Setting up ng-zen...');
9
10
 
11
+ const rules: Rule[] = [];
12
+
10
13
  if (options.installIconLibrary) {
11
- return installIconLibrary()(tree, context);
14
+ rules.push(installIconLibrary());
15
+ } else {
16
+ rules.push(logIconLibraryManualInstructions());
17
+ }
18
+
19
+ if (options.updateEslint) {
20
+ rules.push(updateEslintConfig());
21
+ } else {
22
+ rules.push(logEslintManualInstructions());
12
23
  }
13
24
 
14
- return logIconLibraryManualInstructions()(tree, context);
25
+ return chain(rules)(tree, context);
15
26
  };
16
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../../src/schematics/ng-add/schema.ts"],"names":[],"mappings":"","sourcesContent":["export interface Schema {\n installIconLibrary?: boolean;\n}\n"]}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../../src/schematics/ng-add/schema.ts"],"names":[],"mappings":"","sourcesContent":["export interface Schema {\n installIconLibrary?: boolean;\n updateEslint?: boolean;\n}\n"]}
@@ -8,6 +8,11 @@
8
8
  "installIconLibrary": {
9
9
  "type": "boolean",
10
10
  "x-prompt": "Would you like to install @hugeicons/core-free-icons? This package provides the icon set for zen-icon component. You can also install it manually later."
11
+ },
12
+ "updateEslint": {
13
+ "type": "boolean",
14
+ "x-prompt": "ESLint config detected. Update it for ng-zen UI components? This adds zen prefix rules and relaxes rules for stories/spec files.",
15
+ "default": true
11
16
  }
12
17
  }
13
18
  }
@@ -1,3 +1,4 @@
1
1
  export interface Schema {
2
2
  installIconLibrary?: boolean;
3
+ updateEslint?: boolean;
3
4
  }
@@ -40,7 +40,7 @@ import { Component, input } from '@angular/core';
40
40
  imports: [NgOptimizedImage],
41
41
  template: `
42
42
  @if (src()) {
43
- <img [alt]="alt()" [ngSrc]="src()" fill />
43
+ <img fill [alt]="alt()" [ngSrc]="src()" />
44
44
  } @else {
45
45
  <ng-content />
46
46
  }
@@ -81,7 +81,7 @@ export const WithSignalForm: Story = {
81
81
  template: `
82
82
  <div style="display: flex; flex-direction: column; gap: 0.5rem;">
83
83
  <div style="display: flex; align-items: center; gap: 0.25rem">
84
- <zen-checkbox [formField]="form.agree" id="agree" />
84
+ <zen-checkbox id="agree" [formField]="form.agree" />
85
85
  <label for="agree">I agree to the terms</label>
86
86
  </div>
87
87
  @if (form.agree().invalid()) {
@@ -39,13 +39,13 @@ import { ZenFormControl } from '../form-control';
39
39
  selector: 'zen-checkbox',
40
40
  template: `
41
41
  <input
42
+ #inputElement
43
+ type="checkbox"
42
44
  [attr.aria-disabled]="disabled()"
43
45
  [attr.aria-invalid]="invalid() || null"
44
46
  [checked]="value()"
45
47
  [disabled]="disabled()"
46
48
  (change)="onInput(inputElement.checked)"
47
- #inputElement
48
- type="checkbox"
49
49
  />
50
50
  @if (inputElement.indeterminate) {
51
51
  ─
@@ -67,8 +67,8 @@ See [GitHub](https://github.com/kstepien3/ng-zen), [MDN Dialog Element](https://
67
67
  template: `
68
68
  <p>{{ message() }}</p>
69
69
  <div style="display: flex; gap: 0.5rem; margin-top: 1rem; justify-content: end">
70
- <button (click)="cancel()" color="danger" variant="filled" zen-btn>Cancel</button>
71
- <button (click)="confirmClick.emit('confirmed!')" zen-btn>Confirm</button>
70
+ <button color="danger" variant="filled" zen-btn (click)="cancel()">Cancel</button>
71
+ <button zen-btn (click)="confirmClick.emit('confirmed!')">Confirm</button>
72
72
  </div>
73
73
  `,
74
74
  standalone: true,
@@ -90,7 +90,7 @@ class DemoDialogContent {
90
90
  // eslint-disable-next-line @angular-eslint/component-selector
91
91
  selector: 'app-service-demo',
92
92
  template: `
93
- <button (click)="openDialog()" zen-btn>Open via Service</button>
93
+ <button zen-btn (click)="openDialog()">Open via Service</button>
94
94
  `,
95
95
  standalone: true,
96
96
  imports: [ZenButton],
@@ -62,7 +62,7 @@ interface DialogConfig<T, TInputs = ComponentInputs<T>, TOutputs = ComponentOutp
62
62
 
63
63
  /** Reference to an opened dialog. Provides `close()` and `componentInstance`. */
64
64
  class DialogRef<T> {
65
- public componentInstance!: T;
65
+ componentInstance!: T;
66
66
 
67
67
  constructor(private readonly closeFn: () => void) {}
68
68
 
@@ -130,7 +130,7 @@ class ZenDialogService {
130
130
 
131
131
  this.dialogRef.instance.open.set(true);
132
132
 
133
- const { inputs, outputs, ...inputMappings } = config || {};
133
+ const { inputs, outputs, ...inputMappings } = config ?? {};
134
134
 
135
135
  for (const [key, value] of Object.entries(inputMappings)) {
136
136
  if (value !== undefined) {