@rivinia/modal 0.1.0 → 0.2.0
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.
- package/README.md +2 -1
- package/package.json +2 -1
- package/schematics/collection.json +10 -0
- package/schematics/ng-add/index.cjs +101 -0
- package/schematics/ng-add/schema.json +19 -0
package/README.md
CHANGED
|
@@ -8,13 +8,14 @@ Headless modal manager for Angular 22+. Stack/Queue strategies, typed
|
|
|
8
8
|
zero styles, zero router dependency. A future `@rivinia/modal/ui` entry point
|
|
9
9
|
will render this state; Core never imports UI.
|
|
10
10
|
|
|
11
|
-
- Version: **0.
|
|
11
|
+
- Version: **0.2.0**
|
|
12
12
|
- Requires: **Angular `^22.0.0`**, `tslib`
|
|
13
13
|
|
|
14
14
|
## Install
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
17
|
npm install @rivinia/modal
|
|
18
|
+
ng add @rivinia/modal # wires provideRiviniaModal() into app.config.ts
|
|
18
19
|
```
|
|
19
20
|
|
|
20
21
|
```ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rivinia/modal",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Headless modal manager for Angular: stack/queue strategies, typed results, guards, ownership.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"@angular/core": "^22.0.0"
|
|
15
15
|
},
|
|
16
16
|
"sideEffects": false,
|
|
17
|
+
"schematics": "./schematics/collection.json",
|
|
17
18
|
"module": "fesm2022/rivinia-modal.mjs",
|
|
18
19
|
"typings": "types/rivinia-modal.d.ts",
|
|
19
20
|
"exports": {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../node_modules/@angular-devkit/schematics/collection-schema.json",
|
|
3
|
+
"schematics": {
|
|
4
|
+
"ng-add": {
|
|
5
|
+
"description": "Add provideRiviniaModal() to the application config.",
|
|
6
|
+
"factory": "./ng-add/index.cjs#ngAdd",
|
|
7
|
+
"schema": "./ng-add/schema.json"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ngAdd = ngAdd;
|
|
4
|
+
const schematics_1 = require("@angular-devkit/schematics");
|
|
5
|
+
const PROVIDE_IMPORT = `import { provideRiviniaModal } from '@rivinia/modal';`;
|
|
6
|
+
/**
|
|
7
|
+
* `ng add @rivinia/modal` — wires the manager into a standalone app config.
|
|
8
|
+
*
|
|
9
|
+
* - Never overwrites user files; only inserts one import + one provider.
|
|
10
|
+
* - Idempotent: safe to run twice. No prompts by design (strategy is a
|
|
11
|
+
* one-line edit; pass `--strategy queue` or edit afterwards).
|
|
12
|
+
* - Rendering outlet (`<rv-modal-outlet/>` in a future `/ui` entry) is a
|
|
13
|
+
* layout decision the schematic never makes for you.
|
|
14
|
+
*/
|
|
15
|
+
function ngAdd(options) {
|
|
16
|
+
return (tree, context) => {
|
|
17
|
+
let configPath;
|
|
18
|
+
try {
|
|
19
|
+
configPath = findAppConfig(tree, options.project);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
context.logger.warn(`[rivinia/modal] workspace lookup failed (${error instanceof Error ? error.message : error}) — skipping. ` +
|
|
23
|
+
`Add provideRiviniaModal() manually (see README).`);
|
|
24
|
+
return tree;
|
|
25
|
+
}
|
|
26
|
+
if (!configPath || !tree.exists(configPath)) {
|
|
27
|
+
context.logger.warn(`[rivinia/modal] app.config.ts not found — skipping. ` +
|
|
28
|
+
`Add provideRiviniaModal() manually (see README).`);
|
|
29
|
+
return tree;
|
|
30
|
+
}
|
|
31
|
+
let content = tree.read(configPath)?.toString('utf-8') ?? '';
|
|
32
|
+
if (!content) {
|
|
33
|
+
throw new schematics_1.SchematicsException(`[rivinia/modal] ${configPath} is empty.`);
|
|
34
|
+
}
|
|
35
|
+
const provideCall = options.strategy !== undefined ? `provideRiviniaModal({ strategy: '${options.strategy}' })` : 'provideRiviniaModal()';
|
|
36
|
+
let changed = false;
|
|
37
|
+
if (!content.includes(PROVIDE_IMPORT)) {
|
|
38
|
+
content = insertAfterLastImport(content, PROVIDE_IMPORT);
|
|
39
|
+
changed = true;
|
|
40
|
+
}
|
|
41
|
+
if (!content.includes('provideRiviniaModal(')) {
|
|
42
|
+
content = insertProvider(content, provideCall);
|
|
43
|
+
changed = true;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
context.logger.info('[rivinia/modal] provideRiviniaModal() already present — skipped.');
|
|
47
|
+
}
|
|
48
|
+
if (changed) {
|
|
49
|
+
tree.overwrite(configPath, content);
|
|
50
|
+
context.logger.info(`[rivinia/modal] wired into ${configPath}.`);
|
|
51
|
+
}
|
|
52
|
+
return tree;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function defaultProjectName(tree, requested) {
|
|
56
|
+
if (requested)
|
|
57
|
+
return requested;
|
|
58
|
+
const angularJson = tree.read('/angular.json')?.toString('utf-8');
|
|
59
|
+
if (!angularJson) {
|
|
60
|
+
throw new schematics_1.SchematicsException('[rivinia/modal] angular.json not found.');
|
|
61
|
+
}
|
|
62
|
+
const workspace = JSON.parse(angularJson);
|
|
63
|
+
if (workspace.defaultProject && typeof workspace.defaultProject === 'string') {
|
|
64
|
+
return workspace.defaultProject;
|
|
65
|
+
}
|
|
66
|
+
const names = Object.keys(workspace.projects ?? {});
|
|
67
|
+
if (names.length === 0) {
|
|
68
|
+
throw new schematics_1.SchematicsException('[rivinia/modal] no projects in angular.json.');
|
|
69
|
+
}
|
|
70
|
+
return names[0];
|
|
71
|
+
}
|
|
72
|
+
function findAppConfig(tree, requestedProject) {
|
|
73
|
+
const angularJson = tree.read('/angular.json')?.toString('utf-8');
|
|
74
|
+
if (!angularJson)
|
|
75
|
+
return null;
|
|
76
|
+
const workspace = JSON.parse(angularJson);
|
|
77
|
+
const name = defaultProjectName(tree, requestedProject);
|
|
78
|
+
const project = workspace.projects?.[name];
|
|
79
|
+
if (!project)
|
|
80
|
+
return null;
|
|
81
|
+
const sourceRoot = project.sourceRoot ?? (project.root ? `${project.root}/src` : 'src');
|
|
82
|
+
return `/${sourceRoot}/app/app.config.ts`;
|
|
83
|
+
}
|
|
84
|
+
function insertAfterLastImport(content, line) {
|
|
85
|
+
const lines = content.split('\n');
|
|
86
|
+
let idx = -1;
|
|
87
|
+
for (let i = 0; i < lines.length; i++) {
|
|
88
|
+
if (/^\s*import\s/.test(lines[i]))
|
|
89
|
+
idx = i;
|
|
90
|
+
}
|
|
91
|
+
lines.splice(idx + 1, 0, line);
|
|
92
|
+
return lines.join('\n');
|
|
93
|
+
}
|
|
94
|
+
function insertProvider(content, call) {
|
|
95
|
+
const match = /providers\s*:\s*\[/.exec(content);
|
|
96
|
+
if (!match) {
|
|
97
|
+
throw new schematics_1.SchematicsException('[rivinia/modal] no `providers: [` array found in app.config.ts — add providers manually.');
|
|
98
|
+
}
|
|
99
|
+
const at = match.index + match[0].length;
|
|
100
|
+
return `${content.slice(0, at)}\n ${call},${content.slice(at)}`;
|
|
101
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/schema",
|
|
3
|
+
"$id": "rivinia-modal-ng-add",
|
|
4
|
+
"title": "Rivinia Modal ng-add options",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"strategy": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "Ordering policy for provideRiviniaModal({ strategy }). Omit for the 'stack' default.",
|
|
10
|
+
"enum": ["stack", "queue"]
|
|
11
|
+
},
|
|
12
|
+
"project": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "Angular CLI project name — only for multi-app workspaces. Defaults to the workspace default project.",
|
|
15
|
+
"default": ""
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"required": []
|
|
19
|
+
}
|