@daltonr/pathwrite-angular 0.1.1 → 0.1.3
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 +104 -0
- package/dist/index.css +226 -0
- package/dist/shell.js +2 -2
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -78,3 +78,107 @@ public readonly currentStep = computed(() => this.snapshot()?.stepId ?? null);
|
|
|
78
78
|
|---------|---------|
|
|
79
79
|
| `@angular/core` | `>=16.0.0` |
|
|
80
80
|
| `rxjs` | `>=7.0.0` |
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Default UI — `<pw-shell>`
|
|
85
|
+
|
|
86
|
+
The Angular adapter ships an optional shell component that renders a complete progress indicator, step content area, and navigation buttons out of the box. You only need to define the per-step content.
|
|
87
|
+
|
|
88
|
+
The shell lives in a separate entry point so that headless-only usage does not pull in the Angular compiler:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { PathShellComponent, PathStepDirective } from "@daltonr/pathwrite-angular/shell";
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Usage
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
@Component({
|
|
98
|
+
imports: [PathShellComponent, PathStepDirective],
|
|
99
|
+
template: `
|
|
100
|
+
<pw-shell [path]="myPath" [initialData]="{ name: '' }" (completed)="onDone($event)">
|
|
101
|
+
<ng-template pwStep="details"><app-details-form /></ng-template>
|
|
102
|
+
<ng-template pwStep="review"><app-review-panel /></ng-template>
|
|
103
|
+
</pw-shell>
|
|
104
|
+
`
|
|
105
|
+
})
|
|
106
|
+
export class MyComponent {
|
|
107
|
+
protected myPath = coursePath;
|
|
108
|
+
protected onDone(data: PathData) { console.log("Done!", data); }
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Each `<ng-template pwStep="<stepId>">` is rendered when the active step matches `stepId`. The shell handles all navigation internally.
|
|
113
|
+
|
|
114
|
+
### Context sharing
|
|
115
|
+
|
|
116
|
+
`PathShellComponent` provides a `PathFacade` instance at the component level. Step content components can inject it directly without a separate provider:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
@Component({
|
|
120
|
+
template: `
|
|
121
|
+
<input [value]="snapshot()?.data?.name ?? ''"
|
|
122
|
+
(input)="facade.setData('name', $event.target.value)" />
|
|
123
|
+
`
|
|
124
|
+
})
|
|
125
|
+
export class DetailsFormComponent {
|
|
126
|
+
protected readonly facade = inject(PathFacade);
|
|
127
|
+
protected readonly snapshot = toSignal(this.facade.state$, { initialValue: null });
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Inputs
|
|
132
|
+
|
|
133
|
+
| Input | Type | Default | Description |
|
|
134
|
+
|-------|------|---------|-------------|
|
|
135
|
+
| `path` | `PathDefinition` | *required* | The path definition to drive. |
|
|
136
|
+
| `initialData` | `PathData` | `{}` | Initial data passed to `facade.start()`. |
|
|
137
|
+
| `autoStart` | `boolean` | `true` | Start the path automatically on `ngOnInit`. |
|
|
138
|
+
| `backLabel` | `string` | `"Back"` | Back button label. |
|
|
139
|
+
| `nextLabel` | `string` | `"Next"` | Next button label. |
|
|
140
|
+
| `finishLabel` | `string` | `"Finish"` | Finish button label (last step). |
|
|
141
|
+
| `cancelLabel` | `string` | `"Cancel"` | Cancel button label. |
|
|
142
|
+
| `hideCancel` | `boolean` | `false` | Hide the Cancel button. |
|
|
143
|
+
| `hideProgress` | `boolean` | `false` | Hide the progress indicator. |
|
|
144
|
+
|
|
145
|
+
### Outputs
|
|
146
|
+
|
|
147
|
+
| Output | Payload | Description |
|
|
148
|
+
|--------|---------|-------------|
|
|
149
|
+
| `(completed)` | `PathData` | Emitted when the path finishes naturally. |
|
|
150
|
+
| `(cancelled)` | `PathData` | Emitted when the path is cancelled. |
|
|
151
|
+
| `(pathEvent)` | `PathEvent` | Emitted for every engine event. |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Styling
|
|
156
|
+
|
|
157
|
+
Import the optional stylesheet for sensible default styles. All visual values are CSS custom properties (`--pw-*`) so you can theme without overriding selectors.
|
|
158
|
+
|
|
159
|
+
### In `angular.json` (recommended)
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
"styles": [
|
|
163
|
+
"src/styles.css",
|
|
164
|
+
"node_modules/@daltonr/pathwrite-angular/dist/index.css"
|
|
165
|
+
]
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### In a global stylesheet
|
|
169
|
+
|
|
170
|
+
```css
|
|
171
|
+
@import "@daltonr/pathwrite-angular/styles.css";
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Theming
|
|
175
|
+
|
|
176
|
+
Override any `--pw-*` variable to customise the appearance:
|
|
177
|
+
|
|
178
|
+
```css
|
|
179
|
+
:root {
|
|
180
|
+
--pw-color-primary: #8b5cf6;
|
|
181
|
+
--pw-shell-radius: 12px;
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Pathwrite — Default Shell Stylesheet
|
|
3
|
+
*
|
|
4
|
+
* Optional CSS for the <PathShell> / <pw-shell> default UI components.
|
|
5
|
+
* Import this file if you want sensible out-of-the-box styling.
|
|
6
|
+
* Every visual value is a CSS custom property (--pw-*) so you can
|
|
7
|
+
* theme the shell without overriding selectors.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* import "@daltonr/pathwrite-shell.css"; // bundler import
|
|
11
|
+
* <link href="pathwrite/shell.css" ...> // HTML link
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/* ------------------------------------------------------------------ */
|
|
15
|
+
/* Custom property defaults */
|
|
16
|
+
/* ------------------------------------------------------------------ */
|
|
17
|
+
:root {
|
|
18
|
+
/* Layout */
|
|
19
|
+
--pw-shell-max-width: 720px;
|
|
20
|
+
--pw-shell-padding: 24px;
|
|
21
|
+
--pw-shell-gap: 20px;
|
|
22
|
+
--pw-shell-radius: 10px;
|
|
23
|
+
|
|
24
|
+
/* Colours */
|
|
25
|
+
--pw-color-bg: #ffffff;
|
|
26
|
+
--pw-color-border: #dbe4f0;
|
|
27
|
+
--pw-color-text: #1f2937;
|
|
28
|
+
--pw-color-muted: #5b677a;
|
|
29
|
+
--pw-color-primary: #2563eb;
|
|
30
|
+
--pw-color-primary-light: rgba(37, 99, 235, 0.12);
|
|
31
|
+
--pw-color-btn-bg: #f8fbff;
|
|
32
|
+
--pw-color-btn-border: #c2d0e5;
|
|
33
|
+
|
|
34
|
+
/* Progress */
|
|
35
|
+
--pw-dot-size: 32px;
|
|
36
|
+
--pw-dot-font-size: 13px;
|
|
37
|
+
--pw-track-height: 4px;
|
|
38
|
+
|
|
39
|
+
/* Buttons */
|
|
40
|
+
--pw-btn-padding: 8px 16px;
|
|
41
|
+
--pw-btn-radius: 6px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* ------------------------------------------------------------------ */
|
|
45
|
+
/* Shell root */
|
|
46
|
+
/* ------------------------------------------------------------------ */
|
|
47
|
+
.pw-shell {
|
|
48
|
+
max-width: var(--pw-shell-max-width);
|
|
49
|
+
margin: 0 auto;
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
gap: var(--pw-shell-gap);
|
|
53
|
+
padding: var(--pw-shell-padding);
|
|
54
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
55
|
+
color: var(--pw-color-text);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* ------------------------------------------------------------------ */
|
|
59
|
+
/* Empty state */
|
|
60
|
+
/* ------------------------------------------------------------------ */
|
|
61
|
+
.pw-shell__empty {
|
|
62
|
+
text-align: center;
|
|
63
|
+
padding: 32px 16px;
|
|
64
|
+
color: var(--pw-color-muted);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.pw-shell__start-btn {
|
|
68
|
+
margin-top: 12px;
|
|
69
|
+
border: 1px solid var(--pw-color-btn-border);
|
|
70
|
+
background: var(--pw-color-btn-bg);
|
|
71
|
+
color: var(--pw-color-text);
|
|
72
|
+
padding: var(--pw-btn-padding);
|
|
73
|
+
border-radius: var(--pw-btn-radius);
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
font-size: 14px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* ------------------------------------------------------------------ */
|
|
79
|
+
/* Header — progress indicator */
|
|
80
|
+
/* ------------------------------------------------------------------ */
|
|
81
|
+
.pw-shell__header {
|
|
82
|
+
background: var(--pw-color-bg);
|
|
83
|
+
border: 1px solid var(--pw-color-border);
|
|
84
|
+
border-radius: var(--pw-shell-radius);
|
|
85
|
+
padding: 20px 24px 16px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.pw-shell__steps {
|
|
89
|
+
display: flex;
|
|
90
|
+
justify-content: space-between;
|
|
91
|
+
margin-bottom: 12px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.pw-shell__step {
|
|
95
|
+
display: flex;
|
|
96
|
+
flex-direction: column;
|
|
97
|
+
align-items: center;
|
|
98
|
+
gap: 6px;
|
|
99
|
+
flex: 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.pw-shell__step-dot {
|
|
103
|
+
width: var(--pw-dot-size);
|
|
104
|
+
height: var(--pw-dot-size);
|
|
105
|
+
border-radius: 50%;
|
|
106
|
+
display: flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
justify-content: center;
|
|
109
|
+
font-size: var(--pw-dot-font-size);
|
|
110
|
+
font-weight: 600;
|
|
111
|
+
border: 2px solid var(--pw-color-border);
|
|
112
|
+
background: var(--pw-color-bg);
|
|
113
|
+
color: var(--pw-color-muted);
|
|
114
|
+
transition: all 0.25s ease;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.pw-shell__step--completed .pw-shell__step-dot {
|
|
118
|
+
background: var(--pw-color-primary);
|
|
119
|
+
border-color: var(--pw-color-primary);
|
|
120
|
+
color: #fff;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.pw-shell__step--current .pw-shell__step-dot {
|
|
124
|
+
border-color: var(--pw-color-primary);
|
|
125
|
+
color: var(--pw-color-primary);
|
|
126
|
+
box-shadow: 0 0 0 3px var(--pw-color-primary-light);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.pw-shell__step-label {
|
|
130
|
+
font-size: 12px;
|
|
131
|
+
color: var(--pw-color-muted);
|
|
132
|
+
text-align: center;
|
|
133
|
+
white-space: nowrap;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.pw-shell__step--current .pw-shell__step-label {
|
|
137
|
+
color: var(--pw-color-primary);
|
|
138
|
+
font-weight: 600;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.pw-shell__step--completed .pw-shell__step-label {
|
|
142
|
+
color: var(--pw-color-text);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Track / fill */
|
|
146
|
+
.pw-shell__track {
|
|
147
|
+
height: var(--pw-track-height);
|
|
148
|
+
background: var(--pw-color-border);
|
|
149
|
+
border-radius: calc(var(--pw-track-height) / 2);
|
|
150
|
+
overflow: hidden;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.pw-shell__track-fill {
|
|
154
|
+
height: 100%;
|
|
155
|
+
background: var(--pw-color-primary);
|
|
156
|
+
border-radius: calc(var(--pw-track-height) / 2);
|
|
157
|
+
transition: width 0.3s ease;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* ------------------------------------------------------------------ */
|
|
161
|
+
/* Body — step content */
|
|
162
|
+
/* ------------------------------------------------------------------ */
|
|
163
|
+
.pw-shell__body {
|
|
164
|
+
background: var(--pw-color-bg);
|
|
165
|
+
border: 1px solid var(--pw-color-border);
|
|
166
|
+
border-radius: var(--pw-shell-radius);
|
|
167
|
+
padding: var(--pw-shell-padding);
|
|
168
|
+
min-height: 120px;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* ------------------------------------------------------------------ */
|
|
172
|
+
/* Footer — navigation buttons */
|
|
173
|
+
/* ------------------------------------------------------------------ */
|
|
174
|
+
.pw-shell__footer {
|
|
175
|
+
display: flex;
|
|
176
|
+
justify-content: space-between;
|
|
177
|
+
align-items: center;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.pw-shell__footer-left,
|
|
181
|
+
.pw-shell__footer-right {
|
|
182
|
+
display: flex;
|
|
183
|
+
gap: 8px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.pw-shell__btn {
|
|
187
|
+
border: 1px solid var(--pw-color-btn-border);
|
|
188
|
+
background: var(--pw-color-btn-bg);
|
|
189
|
+
color: var(--pw-color-text);
|
|
190
|
+
padding: var(--pw-btn-padding);
|
|
191
|
+
border-radius: var(--pw-btn-radius);
|
|
192
|
+
cursor: pointer;
|
|
193
|
+
font-size: 14px;
|
|
194
|
+
transition: background 0.15s ease, border-color 0.15s ease;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.pw-shell__btn:hover:not(:disabled) {
|
|
198
|
+
background: var(--pw-color-border);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.pw-shell__btn:disabled {
|
|
202
|
+
opacity: 0.5;
|
|
203
|
+
cursor: not-allowed;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.pw-shell__btn--next {
|
|
207
|
+
background: var(--pw-color-primary);
|
|
208
|
+
border-color: var(--pw-color-primary);
|
|
209
|
+
color: #fff;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.pw-shell__btn--next:hover:not(:disabled) {
|
|
213
|
+
background: #1d4ed8;
|
|
214
|
+
border-color: #1d4ed8;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.pw-shell__btn--cancel {
|
|
218
|
+
color: var(--pw-color-muted);
|
|
219
|
+
border-color: transparent;
|
|
220
|
+
background: transparent;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.pw-shell__btn--cancel:hover:not(:disabled) {
|
|
224
|
+
background: var(--pw-color-primary-light);
|
|
225
|
+
}
|
|
226
|
+
|
package/dist/shell.js
CHANGED
|
@@ -145,7 +145,7 @@ let PathShellComponent = (() => {
|
|
|
145
145
|
*ngIf="!s.isFirstStep"
|
|
146
146
|
type="button"
|
|
147
147
|
class="pw-shell__btn pw-shell__btn--back"
|
|
148
|
-
[disabled]="s.isNavigating"
|
|
148
|
+
[disabled]="s.isNavigating || !s.canMovePrevious"
|
|
149
149
|
(click)="facade.previous()"
|
|
150
150
|
>{{ backLabel }}</button>
|
|
151
151
|
</div>
|
|
@@ -160,7 +160,7 @@ let PathShellComponent = (() => {
|
|
|
160
160
|
<button
|
|
161
161
|
type="button"
|
|
162
162
|
class="pw-shell__btn pw-shell__btn--next"
|
|
163
|
-
[disabled]="s.isNavigating"
|
|
163
|
+
[disabled]="s.isNavigating || !s.canMoveNext"
|
|
164
164
|
(click)="facade.next()"
|
|
165
165
|
>{{ s.isLastStep ? finishLabel : nextLabel }}</button>
|
|
166
166
|
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@daltonr/pathwrite-angular",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Angular adapter for @daltonr/pathwrite-core — RxJS observables, signal-friendly, with optional <pw-shell> default UI.",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"multi-step",
|
|
18
18
|
"workflow"
|
|
19
19
|
],
|
|
20
|
-
"sideEffects":
|
|
20
|
+
"sideEffects": ["**/*.css"],
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
23
23
|
"types": "./dist/index.d.ts",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"./shell": {
|
|
27
27
|
"types": "./dist/shell.d.ts",
|
|
28
28
|
"import": "./dist/shell.js"
|
|
29
|
-
}
|
|
29
|
+
},
|
|
30
|
+
"./styles.css": "./dist/index.css"
|
|
30
31
|
},
|
|
31
32
|
"main": "dist/index.js",
|
|
32
33
|
"types": "dist/index.d.ts",
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
"LICENSE"
|
|
37
38
|
],
|
|
38
39
|
"scripts": {
|
|
39
|
-
"build": "tsc -p tsconfig.json",
|
|
40
|
+
"build": "tsc -p tsconfig.json && cp ../shell.css dist/index.css",
|
|
40
41
|
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
41
42
|
"prepublishOnly": "npm run clean && npm run build"
|
|
42
43
|
},
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
"rxjs": "^7.0.0"
|
|
47
48
|
},
|
|
48
49
|
"dependencies": {
|
|
49
|
-
"@daltonr/pathwrite-core": "^0.1.
|
|
50
|
+
"@daltonr/pathwrite-core": "^0.1.3"
|
|
50
51
|
},
|
|
51
52
|
"publishConfig": {
|
|
52
53
|
"access": "public"
|