@ssv/ngx.command 4.0.0 → 5.0.0-dev.113
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 +29 -14
- package/fesm2022/ssv-ngx.command.mjs +140 -166
- package/fesm2022/ssv-ngx.command.mjs.map +1 -1
- package/package.json +6 -6
- package/types/ssv-ngx.command.d.ts +228 -0
- package/index.d.ts +0 -192
package/README.md
CHANGED
|
@@ -18,21 +18,22 @@ npm install @ssv/ngx.command
|
|
|
18
18
|
|
|
19
19
|
Choose the version corresponding to your Angular version:
|
|
20
20
|
|
|
21
|
-
|
|
|
21
|
+
| library | Angular |
|
|
22
22
|
| ------- | ------- |
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
23
|
+
| 5.x+ | 17+ |
|
|
24
|
+
| 4.x+ | 17+ |
|
|
25
|
+
| 3.x+ | 17+ |
|
|
26
|
+
| 2.x+ | 10+ |
|
|
27
|
+
| 1.x+ | 4 to 9 |
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
# Usage
|
|
30
31
|
|
|
31
32
|
## Command
|
|
32
|
-
|
|
33
|
+
Create a new instance of `Command`
|
|
33
34
|
|
|
34
35
|
```ts
|
|
35
|
-
import { command
|
|
36
|
+
import { command } from "@ssv/ngx.command";
|
|
36
37
|
|
|
37
38
|
const isValid = signal(false);
|
|
38
39
|
const isValid$ = new BehaviorSubject(false);
|
|
@@ -41,12 +42,13 @@ const isValid$ = new BehaviorSubject(false);
|
|
|
41
42
|
saveCmd = command(() => this.save(), isValid);
|
|
42
43
|
|
|
43
44
|
// async - returns an observable/promise.
|
|
44
|
-
saveCmd =
|
|
45
|
+
saveCmd = command(() => Observable.timer(2000), isValid);
|
|
45
46
|
|
|
46
47
|
// can execute diff ways
|
|
47
48
|
saveCmd = command(() => this.save(), () => isValid()); // reactive fn (signal)
|
|
48
49
|
saveCmd = command(() => this.save(), isValid); // signal
|
|
49
50
|
saveCmd = command(() => this.save(), isValid$); // rx
|
|
51
|
+
saveCmd = command(() => this.save(), false); // boolean (perma disabled)
|
|
50
52
|
```
|
|
51
53
|
|
|
52
54
|
## Command Attribute (Directive)
|
|
@@ -124,10 +126,10 @@ Command creator ref, directive which allows creating Command in the template and
|
|
|
124
126
|
```html
|
|
125
127
|
@for (hero of heroes; track hero.key) {
|
|
126
128
|
<div #actionCmd="ssvCommandRef" [ssvCommandRef]="{host: this, execute: removeHero$, canExecute: isValid$}" class="button-group">
|
|
127
|
-
<button [ssvCommand]="actionCmd.command" [ssvCommandParams]="hero">
|
|
129
|
+
<button [ssvCommand]="actionCmd.command()" [ssvCommandParams]="hero">
|
|
128
130
|
Remove
|
|
129
131
|
</button>
|
|
130
|
-
<button [ssvCommand]="actionCmd.command" [ssvCommandParams]="hero">
|
|
132
|
+
<button [ssvCommand]="actionCmd.command()" [ssvCommandParams]="hero">
|
|
131
133
|
Remove
|
|
132
134
|
</button>
|
|
133
135
|
</div>
|
|
@@ -141,17 +143,30 @@ In order to use with `NgForm` easily, you can use the following utility method.
|
|
|
141
143
|
This will make canExecute respond to `form.valid` and for `form.dirty` - also can optionally disable validity or dirty.
|
|
142
144
|
|
|
143
145
|
```ts
|
|
144
|
-
import {
|
|
146
|
+
import { command, canExecuteFromNgForm, canExecuteFromSignals } from "@ssv/ngx.command";
|
|
145
147
|
|
|
146
|
-
loginCmd =
|
|
148
|
+
loginCmd = command(x => this.login(), canExecuteFromNgForm(this.form));
|
|
147
149
|
|
|
148
150
|
// options - disable dirty check
|
|
149
|
-
loginCmd =
|
|
151
|
+
loginCmd = command(x => this.login(), canExecuteFromNgForm(this.form, {
|
|
150
152
|
dirty: false
|
|
151
153
|
}));
|
|
152
154
|
|
|
153
155
|
// similar functionality using custom signals (or form which provide signals)
|
|
154
|
-
loginCmd =
|
|
156
|
+
loginCmd = command(x => this.login(), canExecuteFromSignals({dirty: $dirty, valid: $valid}));
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Command Input (type)
|
|
160
|
+
Simplifies the definition when used as an input.
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
// For a command with a single parameter:
|
|
164
|
+
readonly myCmd = input.required<CommandInput<MyType>>();
|
|
165
|
+
// For a command with multiple parameters:
|
|
166
|
+
readonly myCmd = input.required<CommandInput<[param1: string, param2: number]>>();
|
|
167
|
+
|
|
168
|
+
// instead of
|
|
169
|
+
readonly myCmd = input.required<Command<(param1: string, param2: number) => unknown>>();
|
|
155
170
|
```
|
|
156
171
|
|
|
157
172
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, assertInInjectionContext, inject, Injector,
|
|
3
|
-
import {
|
|
2
|
+
import { InjectionToken, assertInInjectionContext, inject, Injector, signal, computed, isSignal, Renderer2, ElementRef, ChangeDetectorRef, input, effect, Directive, NgModule } from '@angular/core';
|
|
3
|
+
import { isObservable, lastValueFrom, concat, defer, of, filter, map, distinctUntilChanged, combineLatest } from 'rxjs';
|
|
4
4
|
import { toSignal } from '@angular/core/rxjs-interop';
|
|
5
5
|
import { PristineChangeEvent, StatusChangeEvent } from '@angular/forms';
|
|
6
6
|
|
|
@@ -29,134 +29,87 @@ function provideSsvCommandOptions(options) {
|
|
|
29
29
|
];
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
const COMMAND_ASYNC_DEFAULT_OPTIONS = { isAsync: true };
|
|
32
|
+
// todo: remove
|
|
34
33
|
/** Creates an async {@link Command}. Must be used within an injection context.
|
|
35
|
-
*
|
|
34
|
+
* @deprecated Use {@link command} instead, as it handles both sync and async execute functions.
|
|
36
35
|
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/** Creates a {@link Command}. Must be used within an injection context.
|
|
41
|
-
* NOTE: this auto injects `DestroyRef` and handles auto destroy. {@link ICommand.autoDestroy} should not be used.
|
|
42
|
-
*/
|
|
43
|
-
function command(execute, canExecute$, opts) {
|
|
36
|
+
const commandAsync = command;
|
|
37
|
+
/** Creates a {@link Command}. Must be used within an injection context (or the injector must be provided in the options). */
|
|
38
|
+
function command(execute, canExecute, opts) {
|
|
44
39
|
if (!opts?.injector) {
|
|
45
40
|
assertInInjectionContext(command);
|
|
46
41
|
}
|
|
47
42
|
const injector = opts?.injector ?? inject(Injector);
|
|
48
|
-
const
|
|
49
|
-
const destroyRef = injector.get(DestroyRef);
|
|
50
|
-
const cmd = new Command(execute, canExecute$, isAsync, injector);
|
|
51
|
-
cmd.autoDestroy = false;
|
|
52
|
-
destroyRef.onDestroy(() => {
|
|
53
|
-
// console.warn("[command::destroy]");
|
|
54
|
-
cmd.destroy();
|
|
55
|
-
});
|
|
43
|
+
const cmd = new Command(execute, canExecute, injector);
|
|
56
44
|
return cmd;
|
|
57
45
|
}
|
|
58
46
|
/**
|
|
59
47
|
* Command object used to encapsulate information which is needed to perform an action.
|
|
60
|
-
*
|
|
61
48
|
*/
|
|
62
49
|
class Command {
|
|
50
|
+
_execute;
|
|
63
51
|
get isExecuting() { return this.$isExecuting(); }
|
|
64
52
|
get canExecute() { return this.$canExecute(); }
|
|
65
|
-
$isExecuting = signal(false, ...(ngDevMode ? [{ debugName: "$isExecuting" }] : []));
|
|
66
|
-
$canExecute = computed(() => !this.$isExecuting() && this
|
|
67
|
-
|
|
68
|
-
autoDestroy = true;
|
|
69
|
-
executionPipe$ = new Subject();
|
|
70
|
-
executionPipe$$ = Subscription.EMPTY;
|
|
71
|
-
subscribersCount = 0;
|
|
53
|
+
$isExecuting = signal(false, ...(ngDevMode ? [{ debugName: "$isExecuting" }] : /* istanbul ignore next */ []));
|
|
54
|
+
$canExecute = computed(() => !this.$isExecuting() && this.#canExecute(), ...(ngDevMode ? [{ debugName: "$canExecute" }] : /* istanbul ignore next */ []));
|
|
55
|
+
#canExecute;
|
|
72
56
|
/**
|
|
73
57
|
* Creates an instance of Command.
|
|
74
58
|
*
|
|
75
|
-
* @param execute Execute function to invoke
|
|
59
|
+
* @param execute Execute function to invoke.
|
|
76
60
|
* @param canExecute Observable which determines whether it can execute or not.
|
|
77
|
-
* @param isAsync Indicates that the execute function is async e.g. Observable.
|
|
78
61
|
* @deprecated Use {@link command} or {@link commandAsync} instead for creating instances.
|
|
79
62
|
*/
|
|
80
|
-
constructor(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
? computed(canExecute$)
|
|
84
|
-
: canExecute$;
|
|
85
|
-
this._$canExecute = isSignal(canExecute)
|
|
86
|
-
? canExecute
|
|
87
|
-
: toSignal(canExecute, { initialValue: false, injector });
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
this._$canExecute = signal(true, ...(ngDevMode ? [{ debugName: "_$canExecute" }] : []));
|
|
91
|
-
}
|
|
92
|
-
this.executionPipe$$ = this.buildExecutionPipe(execute, isAsync).subscribe();
|
|
63
|
+
constructor(_execute, canExecute, injector) {
|
|
64
|
+
this._execute = _execute;
|
|
65
|
+
this.#canExecute = this.#buildCanExecuteSignal(canExecute, injector);
|
|
93
66
|
}
|
|
94
|
-
/** Execute function to invoke. */
|
|
67
|
+
/** Execute function to invoke. Returns Promise if the execute function returns Observable, otherwise returns the original type. */
|
|
95
68
|
execute(...args) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
/** Disposes all resources held by subscriptions. */
|
|
100
|
-
destroy() {
|
|
101
|
-
// console.warn("[command::destroy]");
|
|
102
|
-
this.executionPipe$$.unsubscribe();
|
|
103
|
-
}
|
|
104
|
-
subscribe() {
|
|
105
|
-
this.subscribersCount++;
|
|
106
|
-
}
|
|
107
|
-
unsubscribe() {
|
|
108
|
-
this.subscribersCount--;
|
|
109
|
-
// console.log("[command::unsubscribe]", { autoDestroy: this.autoDestroy, subscribersCount: this.subscribersCount });
|
|
110
|
-
if (this.autoDestroy && this.subscribersCount <= 0) {
|
|
111
|
-
this.destroy();
|
|
69
|
+
if (!this.$canExecute()) {
|
|
70
|
+
throw new Error("Command cannot execute in its current state.");
|
|
71
|
+
// return Promise.reject() as ReturnType<TExecute>;
|
|
112
72
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
execute();
|
|
134
|
-
});
|
|
135
|
-
pipe$ = pipe$.pipe(switchMap(args => of(args).pipe(execFn, finalize(() => {
|
|
136
|
-
// console.log("[command::executionPipe$] finalize inner#1 - set idle");
|
|
73
|
+
this.$isExecuting.set(true);
|
|
74
|
+
// console.warn("[command::execute]", args);
|
|
75
|
+
try {
|
|
76
|
+
const result = args.length > 0 ? this._execute(...args) : this._execute();
|
|
77
|
+
if (isObservable(result)) {
|
|
78
|
+
// Convert observable to promise using lastValueFrom
|
|
79
|
+
// This ensures fire-and-forget execution without requiring manual subscription
|
|
80
|
+
// Use defaultValue to handle empty observables (those that complete without emitting)
|
|
81
|
+
const promise = lastValueFrom(result, { defaultValue: undefined })
|
|
82
|
+
.finally(() => this.$isExecuting.set(false));
|
|
83
|
+
return promise;
|
|
84
|
+
}
|
|
85
|
+
else if (result instanceof Promise) {
|
|
86
|
+
// Return promise with proper cleanup
|
|
87
|
+
return result
|
|
88
|
+
.finally(() => this.$isExecuting.set(false));
|
|
89
|
+
}
|
|
90
|
+
// Sync execution
|
|
137
91
|
this.$isExecuting.set(false);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}))), tap(() => {
|
|
142
|
-
// console.log("[command::executionPipe$] tap#2 - set idle");
|
|
143
|
-
// this._isExecuting$.next(false);
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
144
95
|
this.$isExecuting.set(false);
|
|
145
|
-
|
|
146
|
-
|
|
96
|
+
throw err;
|
|
97
|
+
}
|
|
147
98
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
99
|
+
#buildCanExecuteSignal(canExecute, injector) {
|
|
100
|
+
if (canExecute === undefined) {
|
|
101
|
+
return computed(() => true);
|
|
102
|
+
}
|
|
103
|
+
if (isSignal(canExecute)) {
|
|
104
|
+
return canExecute;
|
|
105
|
+
}
|
|
106
|
+
if (typeof canExecute === "function") {
|
|
107
|
+
return computed(canExecute);
|
|
108
|
+
}
|
|
109
|
+
if (typeof canExecute === "boolean") {
|
|
110
|
+
return computed(() => canExecute);
|
|
111
|
+
}
|
|
112
|
+
return toSignal(canExecute, { initialValue: false, injector });
|
|
160
113
|
}
|
|
161
114
|
}
|
|
162
115
|
|
|
@@ -202,6 +155,8 @@ function isAssumedType(x) {
|
|
|
202
155
|
return x !== null && typeof x === "object";
|
|
203
156
|
}
|
|
204
157
|
|
|
158
|
+
const NAME_CAMEL$1 = "ssvCommand";
|
|
159
|
+
// let nextUniqueId = 0;
|
|
205
160
|
/**
|
|
206
161
|
* Controls the state of a component in sync with `Command`.
|
|
207
162
|
*
|
|
@@ -222,13 +177,20 @@ function isAssumedType(x) {
|
|
|
222
177
|
* This is useful for collections (loops) or using multiple actions with different args.
|
|
223
178
|
* *NOTE: This will share the `isExecuting` when used with multiple controls.*
|
|
224
179
|
*
|
|
225
|
-
* #### With single param
|
|
180
|
+
* #### With single param (direct)
|
|
226
181
|
*
|
|
227
182
|
* ```html
|
|
228
|
-
* <button [ssvCommand]="saveCmd" [ssvCommandParams]="
|
|
183
|
+
* <button [ssvCommand]="saveCmd" [ssvCommandParams]="hero">Save</button>
|
|
229
184
|
* ```
|
|
185
|
+
*
|
|
186
|
+
* #### With single param (array)
|
|
187
|
+
*
|
|
188
|
+
* ```html
|
|
189
|
+
* <button [ssvCommand]="saveCmd" [ssvCommandParams]="[hero]">Save</button>
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
230
192
|
* *NOTE: if you have only 1 argument as an array, it should be enclosed within an array e.g. `[['apple', 'banana']]`,
|
|
231
|
-
* else it will spread and you will `arg1: "apple", arg2: "banana"`*
|
|
193
|
+
* else it will spread and you will get `arg1: "apple", arg2: "banana"`*
|
|
232
194
|
*
|
|
233
195
|
* #### With multi params
|
|
234
196
|
* ```html
|
|
@@ -244,8 +206,6 @@ function isAssumedType(x) {
|
|
|
244
206
|
* ```
|
|
245
207
|
*
|
|
246
208
|
*/
|
|
247
|
-
const NAME_CAMEL$1 = "ssvCommand";
|
|
248
|
-
// let nextUniqueId = 0;
|
|
249
209
|
class SsvCommand {
|
|
250
210
|
// readonly id = `${NAME_CAMEL}-${nextUniqueId++}`;
|
|
251
211
|
#options = inject(COMMAND_OPTIONS);
|
|
@@ -253,10 +213,8 @@ class SsvCommand {
|
|
|
253
213
|
#element = inject(ElementRef);
|
|
254
214
|
#cdr = inject(ChangeDetectorRef);
|
|
255
215
|
#injector = inject(Injector);
|
|
256
|
-
commandOrCreator = input.required(...(ngDevMode ?
|
|
257
|
-
|
|
258
|
-
}]));
|
|
259
|
-
ssvCommandOptions = input(this.#options, ...(ngDevMode ? [{ debugName: "ssvCommandOptions" }] : []));
|
|
216
|
+
commandOrCreator = input.required({ ...(ngDevMode ? { debugName: "commandOrCreator" } : /* istanbul ignore next */ {}), alias: `ssvCommand` });
|
|
217
|
+
ssvCommandOptions = input(this.#options, ...(ngDevMode ? [{ debugName: "ssvCommandOptions" }] : /* istanbul ignore next */ []));
|
|
260
218
|
commandOptions = computed(() => {
|
|
261
219
|
const value = this.ssvCommandOptions();
|
|
262
220
|
if (value === this.#options) {
|
|
@@ -266,61 +224,72 @@ class SsvCommand {
|
|
|
266
224
|
...this.#options,
|
|
267
225
|
...value,
|
|
268
226
|
};
|
|
269
|
-
}, ...(ngDevMode ? [{ debugName: "commandOptions" }] : []));
|
|
270
|
-
ssvCommandParams = input(
|
|
271
|
-
commandParams = computed(() =>
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
227
|
+
}, ...(ngDevMode ? [{ debugName: "commandOptions" }] : /* istanbul ignore next */ []));
|
|
228
|
+
ssvCommandParams = input(...(ngDevMode ? [undefined, { debugName: "ssvCommandParams" }] : /* istanbul ignore next */ []));
|
|
229
|
+
commandParams = computed(() => {
|
|
230
|
+
const params = this.ssvCommandParams();
|
|
231
|
+
if (params === undefined) {
|
|
232
|
+
return this.#creatorParams();
|
|
233
|
+
}
|
|
234
|
+
// Normalize single param to array format for consistent handling
|
|
235
|
+
return this.#normalizeParams(params);
|
|
236
|
+
}, ...(ngDevMode ? [{ debugName: "commandParams" }] : /* istanbul ignore next */ []));
|
|
237
|
+
_hostClasses = computed(() => ["ssv-command", this.#executingClass()], ...(ngDevMode ? [{ debugName: "_hostClasses" }] : /* istanbul ignore next */ []));
|
|
238
|
+
#executingClass = computed(() => this.#command().$isExecuting() ? this.commandOptions().executingCssClass : "", ...(ngDevMode ? [{ debugName: "#executingClass" }] : /* istanbul ignore next */ []));
|
|
239
|
+
#creatorParams = signal(undefined, ...(ngDevMode ? [{ debugName: "#creatorParams" }] : /* istanbul ignore next */ []));
|
|
240
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
241
|
+
#command = signal(undefined, ...(ngDevMode ? [{ debugName: "#command" }] : /* istanbul ignore next */ []));
|
|
242
|
+
command = this.#command.asReadonly();
|
|
277
243
|
constructor() {
|
|
278
|
-
const destroyRef = inject(DestroyRef);
|
|
279
|
-
destroyRef.onDestroy(() => {
|
|
280
|
-
this._command?.unsubscribe();
|
|
281
|
-
});
|
|
282
244
|
effect(() => {
|
|
283
|
-
const canExecute = this
|
|
245
|
+
const canExecute = this.#command().$canExecute();
|
|
284
246
|
this.trySetDisabled(!canExecute);
|
|
285
247
|
// console.log("[ssvCommand::canExecute$]", { canExecute: x });
|
|
286
248
|
this.#cdr.markForCheck();
|
|
287
249
|
});
|
|
288
250
|
}
|
|
251
|
+
// todo: afterNextRender
|
|
289
252
|
ngOnInit() {
|
|
290
253
|
const commandOrCreator = this.commandOrCreator();
|
|
291
254
|
// console.log("[ssvCommand::init]", this.#options);
|
|
292
255
|
if (isCommand(commandOrCreator)) {
|
|
293
|
-
this.
|
|
256
|
+
this.#command.set(commandOrCreator);
|
|
294
257
|
}
|
|
295
258
|
else if (isCommandCreator(commandOrCreator)) {
|
|
296
|
-
|
|
297
|
-
this.creatorParams = commandOrCreator.params;
|
|
259
|
+
this.#creatorParams.set(this.#normalizeParams(commandOrCreator.params));
|
|
298
260
|
// todo: find something like this for ivy (or angular10+)
|
|
299
261
|
// const hostComponent = (this.viewContainer as any)._view.component;
|
|
300
262
|
const execFn = commandOrCreator.execute.bind(commandOrCreator.host);
|
|
301
263
|
const params = this.commandParams();
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
264
|
+
let canExec;
|
|
265
|
+
if (commandOrCreator.canExecute instanceof Function) {
|
|
266
|
+
const boundFn = commandOrCreator.canExecute.bind(commandOrCreator.host);
|
|
267
|
+
const result = Array.isArray(params) ? boundFn(...params) : boundFn();
|
|
268
|
+
canExec = result;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
canExec = commandOrCreator.canExecute;
|
|
272
|
+
}
|
|
305
273
|
// console.log("[ssvCommand::init] command creator", {
|
|
306
274
|
// firstParam: params ? params[0] : null,
|
|
307
275
|
// params
|
|
308
276
|
// });
|
|
309
|
-
|
|
277
|
+
const cmd = command(execFn, canExec, { injector: this.#injector });
|
|
278
|
+
this.#command.set(cmd);
|
|
310
279
|
}
|
|
311
280
|
else {
|
|
312
281
|
throw new Error(`${NAME_CAMEL$1}: [${NAME_CAMEL$1}] is not defined properly!`);
|
|
313
282
|
}
|
|
314
|
-
this._command.subscribe();
|
|
315
283
|
}
|
|
316
284
|
_handleClick() {
|
|
317
285
|
const commandParams = this.commandParams();
|
|
318
286
|
// console.log("[ssvCommand::onClick]", commandParams);
|
|
319
287
|
if (Array.isArray(commandParams)) {
|
|
320
|
-
this.
|
|
288
|
+
this.#command().execute(...commandParams);
|
|
321
289
|
}
|
|
322
290
|
else {
|
|
323
|
-
|
|
291
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
292
|
+
this.#command().execute();
|
|
324
293
|
}
|
|
325
294
|
}
|
|
326
295
|
trySetDisabled(disabled) {
|
|
@@ -329,10 +298,19 @@ class SsvCommand {
|
|
|
329
298
|
this.#renderer.setProperty(this.#element.nativeElement, "disabled", disabled);
|
|
330
299
|
}
|
|
331
300
|
}
|
|
332
|
-
|
|
333
|
-
|
|
301
|
+
/** Normalizes params to array format for consistent execution */
|
|
302
|
+
#normalizeParams(params) {
|
|
303
|
+
// If params is already an array, return as-is
|
|
304
|
+
if (Array.isArray(params)) {
|
|
305
|
+
return params;
|
|
306
|
+
}
|
|
307
|
+
// Single non-array param - wrap it
|
|
308
|
+
return [params];
|
|
309
|
+
}
|
|
310
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: SsvCommand, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
311
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.2", type: SsvCommand, isStandalone: true, selector: "[ssvCommand]", inputs: { commandOrCreator: { classPropertyName: "commandOrCreator", publicName: "ssvCommand", isSignal: true, isRequired: true, transformFunction: null }, ssvCommandOptions: { classPropertyName: "ssvCommandOptions", publicName: "ssvCommandOptions", isSignal: true, isRequired: false, transformFunction: null }, ssvCommandParams: { classPropertyName: "ssvCommandParams", publicName: "ssvCommandParams", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "_handleClick()" }, properties: { "class": "_hostClasses()" } }, exportAs: ["ssvCommand"], ngImport: i0 });
|
|
334
312
|
}
|
|
335
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
313
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: SsvCommand, decorators: [{
|
|
336
314
|
type: Directive,
|
|
337
315
|
args: [{
|
|
338
316
|
selector: `[${NAME_CAMEL$1}]`,
|
|
@@ -340,6 +318,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
340
318
|
"[class]": "_hostClasses()",
|
|
341
319
|
"(click)": "_handleClick()",
|
|
342
320
|
},
|
|
321
|
+
// todo: handle keydown/enter?
|
|
343
322
|
exportAs: NAME_CAMEL$1,
|
|
344
323
|
standalone: true,
|
|
345
324
|
}]
|
|
@@ -353,10 +332,10 @@ const NAME_CAMEL = "ssvCommandRef";
|
|
|
353
332
|
* ### Most common usage
|
|
354
333
|
* ```html
|
|
355
334
|
* <div #actionCmd="ssvCommandRef" [ssvCommandRef]="{host: this, execute: removeHero$, canExecute: isValid$}">
|
|
356
|
-
* <button [ssvCommand]="actionCmd.command" [ssvCommandParams]="hero">
|
|
335
|
+
* <button [ssvCommand]="actionCmd.command()" [ssvCommandParams]="[hero]">
|
|
357
336
|
* Remove
|
|
358
337
|
* </button>
|
|
359
|
-
* <button [ssvCommand]="actionCmd.command" [ssvCommandParams]="hero">
|
|
338
|
+
* <button [ssvCommand]="actionCmd.command()" [ssvCommandParams]="[hero]">
|
|
360
339
|
* Remove
|
|
361
340
|
* </button>
|
|
362
341
|
* </div>
|
|
@@ -365,39 +344,34 @@ const NAME_CAMEL = "ssvCommandRef";
|
|
|
365
344
|
*/
|
|
366
345
|
class SsvCommandRef {
|
|
367
346
|
#injector = inject(Injector);
|
|
368
|
-
commandCreator = input.required(...(ngDevMode ?
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
constructor() {
|
|
374
|
-
const destroyRef = inject(DestroyRef);
|
|
375
|
-
destroyRef.onDestroy(() => {
|
|
376
|
-
this._command?.unsubscribe();
|
|
377
|
-
});
|
|
378
|
-
}
|
|
347
|
+
commandCreator = input.required({ ...(ngDevMode ? { debugName: "commandCreator" } : /* istanbul ignore next */ {}), alias: `ssvCommandRef` });
|
|
348
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
349
|
+
#command = signal(undefined, ...(ngDevMode ? [{ debugName: "#command" }] : /* istanbul ignore next */ []));
|
|
350
|
+
command = this.#command.asReadonly();
|
|
351
|
+
// todo: use afterNextRender
|
|
379
352
|
ngOnInit() {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
const
|
|
353
|
+
const commandOrCreator = this.commandCreator();
|
|
354
|
+
if (isCommandCreator(commandOrCreator)) {
|
|
355
|
+
const commandCreator = commandOrCreator;
|
|
383
356
|
const execFn = commandCreator.execute.bind(commandCreator.host);
|
|
384
|
-
|
|
357
|
+
const cmd = command(execFn, commandCreator.canExecute, { injector: this.#injector });
|
|
358
|
+
this.#command.set(cmd);
|
|
385
359
|
}
|
|
386
360
|
else {
|
|
387
361
|
throw new Error(`${NAME_CAMEL}: [${NAME_CAMEL}] is not defined properly!`);
|
|
388
362
|
}
|
|
389
363
|
}
|
|
390
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
391
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
364
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: SsvCommandRef, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
365
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.2", type: SsvCommandRef, isStandalone: true, selector: "[ssvCommandRef]", inputs: { commandCreator: { classPropertyName: "commandCreator", publicName: "ssvCommandRef", isSignal: true, isRequired: true, transformFunction: null } }, exportAs: ["ssvCommandRef"], ngImport: i0 });
|
|
392
366
|
}
|
|
393
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
367
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: SsvCommandRef, decorators: [{
|
|
394
368
|
type: Directive,
|
|
395
369
|
args: [{
|
|
396
370
|
selector: `[${NAME_CAMEL}]`,
|
|
397
371
|
exportAs: NAME_CAMEL,
|
|
398
372
|
standalone: true,
|
|
399
373
|
}]
|
|
400
|
-
}],
|
|
374
|
+
}], propDecorators: { commandCreator: [{ type: i0.Input, args: [{ isSignal: true, alias: "ssvCommandRef", required: true }] }] } });
|
|
401
375
|
|
|
402
376
|
const EXPORTED_IMPORTS = [
|
|
403
377
|
SsvCommand,
|
|
@@ -405,13 +379,13 @@ const EXPORTED_IMPORTS = [
|
|
|
405
379
|
];
|
|
406
380
|
/** @deprecated Use standalone instead. */
|
|
407
381
|
class SsvCommandModule {
|
|
408
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
409
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "
|
|
382
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: SsvCommandModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
383
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.2", ngImport: i0, type: SsvCommandModule, imports: [SsvCommand,
|
|
410
384
|
SsvCommandRef], exports: [SsvCommand,
|
|
411
385
|
SsvCommandRef] });
|
|
412
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "
|
|
386
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: SsvCommandModule });
|
|
413
387
|
}
|
|
414
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
388
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: SsvCommandModule, decorators: [{
|
|
415
389
|
type: NgModule,
|
|
416
390
|
args: [{
|
|
417
391
|
imports: [EXPORTED_IMPORTS],
|
|
@@ -419,11 +393,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
419
393
|
}]
|
|
420
394
|
}] });
|
|
421
395
|
|
|
422
|
-
const VERSION = "
|
|
396
|
+
const VERSION = "5.0.0-dev.113";
|
|
423
397
|
|
|
424
398
|
/**
|
|
425
399
|
* Generated bundle index. Do not edit.
|
|
426
400
|
*/
|
|
427
401
|
|
|
428
|
-
export { COMMAND_OPTIONS, Command,
|
|
402
|
+
export { COMMAND_OPTIONS, Command, SsvCommand, SsvCommandModule, SsvCommandRef, VERSION, canExecuteFromNgForm, canExecuteFromSignals, command, commandAsync, isCommand, isCommandCreator, provideSsvCommandOptions };
|
|
429
403
|
//# sourceMappingURL=ssv-ngx.command.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssv-ngx.command.mjs","sources":["../../../../libs/ngx.command/src/command.options.ts","../../../../libs/ngx.command/src/command.ts","../../../../libs/ngx.command/src/command.util.ts","../../../../libs/ngx.command/src/command.directive.ts","../../../../libs/ngx.command/src/command-ref.directive.ts","../../../../libs/ngx.command/src/command.module.ts","../../../../libs/ngx.command/src/version.ts","../../../../libs/ngx.command/src/ssv-ngx.command.ts"],"sourcesContent":["import { InjectionToken, type Provider } from \"@angular/core\";\n\nexport interface CommandOptions {\n\t/**\n\t * Css Class which gets added/removed on the Command element's host while Command `isExecuting$`.\n\t */\n\texecutingCssClass: string;\n\n\t/** Determines whether the disabled will be handled by the directive or not.\n\t * Disable handled by directive's doesn't always play nice when used with other component/pipe/directive and they also handle disabled.\n\t * This disables the handling manually and need to pass explicitly `[disabled]=\"!saveCmd.canExecute\"`.\n\t */\n\thandleDisabled: boolean;\n}\n\nconst DEFAULT_OPTIONS = Object.freeze<CommandOptions>({\n\texecutingCssClass: \"executing\",\n\thandleDisabled: true,\n});\n\nexport const COMMAND_OPTIONS = new InjectionToken<CommandOptions>(\"SSV_COMMAND_OPTIONS\", {\n\tfactory: () => DEFAULT_OPTIONS,\n});\n\nexport function provideSsvCommandOptions(\n\toptions: Partial<CommandOptions> | ((defaults: Readonly<CommandOptions>) => Partial<CommandOptions>)\n): Provider[] {\n\treturn [\n\t\t{\n\t\t\tprovide: COMMAND_OPTIONS,\n\t\t\tuseFactory: () => {\n\t\t\t\tlet opts = typeof options === \"function\" ? options(DEFAULT_OPTIONS) : options;\n\t\t\t\topts = opts\n\t\t\t\t\t? {\n\t\t\t\t\t\t...DEFAULT_OPTIONS,\n\t\t\t\t\t\t...opts,\n\t\t\t\t\t}\n\t\t\t\t\t: DEFAULT_OPTIONS;\n\t\t\t\treturn opts;\n\t\t\t},\n\t\t},\n\t];\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n\tObservable, Subscription, Subject, of, EMPTY,\n\ttap, filter, switchMap, catchError, finalize, take,\n} from \"rxjs\";\nimport { toSignal } from \"@angular/core/rxjs-interop\";\nimport type { CanExecute, ExecuteAsyncFn, ExecuteFn, ICommand } from \"./command.model\";\nimport { assertInInjectionContext, computed, DestroyRef, inject, Injector, isSignal, signal, type Signal } from \"@angular/core\";\n\nexport interface CommandCreateOptions {\n\tisAsync: boolean,\n\tinjector?: Injector;\n}\n\nconst COMMAND_ASYNC_DEFAULT_OPTIONS: CommandCreateOptions = { isAsync: true };\n\n/** Creates an async {@link Command}. Must be used within an injection context.\n * NOTE: this auto injects `DestroyRef` and handles auto destroy. {@link ICommand.autoDestroy} should not be used.\n */\nexport function commandAsync(\n\texecute: ExecuteAsyncFn,\n\tcanExecute$?: CanExecute,\n\topts?: Omit<CommandCreateOptions, \"isAsync\">,\n): Command {\n\treturn command(execute, canExecute$, opts ? { ...opts, ...COMMAND_ASYNC_DEFAULT_OPTIONS } : COMMAND_ASYNC_DEFAULT_OPTIONS);\n}\n\n/** Creates a {@link Command}. Must be used within an injection context.\n * NOTE: this auto injects `DestroyRef` and handles auto destroy. {@link ICommand.autoDestroy} should not be used.\n */\nexport function command(\n\texecute: ExecuteFn,\n\tcanExecute$?: CanExecute,\n\topts?: CommandCreateOptions,\n): Command {\n\tif (!opts?.injector) {\n\t\tassertInInjectionContext(command);\n\t}\n\tconst injector = opts?.injector ?? inject(Injector);\n\tconst isAsync = opts?.isAsync ?? false;\n\tconst destroyRef = injector.get(DestroyRef);\n\tconst cmd = new Command(execute, canExecute$, isAsync, injector);\n\tcmd.autoDestroy = false;\n\n\tdestroyRef.onDestroy(() => {\n\t\t// console.warn(\"[command::destroy]\");\n\t\tcmd.destroy();\n\t});\n\treturn cmd;\n}\n\n/**\n * Command object used to encapsulate information which is needed to perform an action.\n *\n */\nexport class Command implements ICommand {\n\n\tget isExecuting(): boolean { return this.$isExecuting(); }\n\n\tget canExecute(): boolean { return this.$canExecute(); }\n\n\treadonly $isExecuting = signal(false);\n\treadonly $canExecute = computed(() => !this.$isExecuting() && this._$canExecute());\n\n\tprivate readonly _$canExecute: Signal<boolean>;\n\n\tautoDestroy = true;\n\n\tprivate executionPipe$ = new Subject<unknown[] | undefined>();\n\tprivate executionPipe$$ = Subscription.EMPTY;\n\tprivate subscribersCount = 0;\n\n\t/**\n\t * Creates an instance of Command.\n\t *\n\t * @param execute Execute function to invoke - use `isAsync: true` when `Observable<any>`.\n\t * @param canExecute Observable which determines whether it can execute or not.\n\t * @param isAsync Indicates that the execute function is async e.g. Observable.\n\t * @deprecated Use {@link command} or {@link commandAsync} instead for creating instances.\n\t */\n\tconstructor(\n\t\texecute: ExecuteFn,\n\t\tcanExecute$?: CanExecute,\n\t\tisAsync?: boolean,\n\t\tinjector?: Injector,\n\t) {\n\t\tif (canExecute$) {\n\t\t\tconst canExecute = typeof canExecute$ === \"function\"\n\t\t\t\t? computed(canExecute$)\n\t\t\t\t: canExecute$;\n\t\t\tthis._$canExecute = isSignal(canExecute)\n\t\t\t\t? canExecute\n\t\t\t\t: toSignal(canExecute, { initialValue: false, injector });\n\t\t} else {\n\t\t\tthis._$canExecute = signal(true);\n\t\t}\n\t\tthis.executionPipe$$ = this.buildExecutionPipe(execute, isAsync).subscribe();\n\t}\n\n\t/** Execute function to invoke. */\n\texecute(...args: unknown[]): void {\n\t\t// console.warn(\"[command::execute]\", args);\n\t\tthis.executionPipe$.next(args);\n\t}\n\n\t/** Disposes all resources held by subscriptions. */\n\tdestroy(): void {\n\t\t// console.warn(\"[command::destroy]\");\n\t\tthis.executionPipe$$.unsubscribe();\n\t}\n\n\tsubscribe(): void {\n\t\tthis.subscribersCount++;\n\t}\n\n\tunsubscribe(): void {\n\t\tthis.subscribersCount--;\n\t\t// console.log(\"[command::unsubscribe]\", { autoDestroy: this.autoDestroy, subscribersCount: this.subscribersCount });\n\t\tif (this.autoDestroy && this.subscribersCount <= 0) {\n\t\t\tthis.destroy();\n\t\t}\n\t}\n\n\tprivate buildExecutionPipe(execute: (...args: unknown[]) => any, isAsync?: boolean): Observable<unknown> {\n\t\tlet pipe$ = this.executionPipe$.pipe(\n\t\t\t// tap(x => console.warn(\">>>> executionPipe\", this._canExecute)),\n\t\t\tfilter(() => this.$canExecute()),\n\t\t\ttap(() => {\n\t\t\t\t// console.log(\"[command::executionPipe$] do#1 - set execute\", { args: x });\n\t\t\t\tthis.$isExecuting.set(true);\n\t\t\t})\n\t\t);\n\n\t\tconst execFn = isAsync\n\t\t\t? switchMap<unknown[] | undefined, any[]>(args => {\n\t\t\t\tif (args) {\n\t\t\t\t\treturn execute(...args);\n\t\t\t\t}\n\t\t\t\treturn execute();\n\t\t\t})\n\t\t\t: tap((args: unknown[] | undefined) => {\n\t\t\t\tif (args) {\n\t\t\t\t\texecute(...args);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\texecute();\n\t\t\t});\n\n\t\tpipe$ = pipe$.pipe(\n\t\t\tswitchMap(args => of(args).pipe(\n\t\t\t\texecFn,\n\t\t\t\tfinalize(() => {\n\t\t\t\t\t// console.log(\"[command::executionPipe$] finalize inner#1 - set idle\");\n\t\t\t\t\tthis.$isExecuting.set(false);\n\t\t\t\t}),\n\t\t\t\ttake(1),\n\t\t\t\tcatchError(error => {\n\t\t\t\t\tconsole.error(\"Unhandled execute error\", error);\n\t\t\t\t\treturn EMPTY;\n\t\t\t\t}),\n\t\t\t)),\n\t\t\ttap(() => {\n\t\t\t\t// console.log(\"[command::executionPipe$] tap#2 - set idle\");\n\t\t\t\t// this._isExecuting$.next(false);\n\t\t\t\tthis.$isExecuting.set(false);\n\t\t\t}),\n\t\t);\n\t\treturn pipe$;\n\t}\n\n}\n\n/**\n * Async Command object used to encapsulate information which is needed to perform an action,\n * which takes an execute function as Observable/Promise.\n * @deprecated Use {@link commandAsync} instead.\n */\nexport class CommandAsync extends Command {\n\n\t/**\n\t * @deprecated Use {@link commandAsync} instead to create an instance.\n\t */\n\tconstructor(\n\t\texecute: ExecuteAsyncFn,\n\t\tcanExecute$?: CanExecute,\n\t) {\n\t\tsuper(execute, canExecute$, true);\n\t}\n\n}\n","import { AbstractControl, PristineChangeEvent, StatusChangeEvent } from \"@angular/forms\";\nimport { Observable, map, distinctUntilChanged, filter, combineLatest, of, defer, concat } from \"rxjs\";\n\nimport { CommandCreator, ICommand } from \"./command.model\";\nimport { Command } from \"./command\";\nimport { type Signal, computed } from \"@angular/core\";\n\n/** Determines whether the arg object is of type `Command`. */\nexport function isCommand(arg: unknown): arg is ICommand {\n\treturn arg instanceof Command;\n}\n\n/** Determines whether the arg object is of type `CommandCreator`. */\nexport function isCommandCreator(arg: unknown): arg is CommandCreator {\n\tif (arg instanceof Command) {\n\t\treturn false;\n\t} else if (isAssumedType<CommandCreator>(arg) && arg.execute && arg.host) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nexport interface CanExecuteFormOptions {\n\t/** Determines whether to check for validity. (defaults: true) */\n\tvalidity?: boolean;\n\n\t/** Determines whether to check whether UI has been touched. (defaults: true) */\n\tdirty?: boolean;\n}\n\nconst CAN_EXECUTE_FORM_OPTIONS_DEFAULTS = Object.freeze<CanExecuteFormOptions>({\n\tvalidity: true,\n\tdirty: true,\n})\n\n/** Get can execute from form validity/pristine as an observable. */\nexport function canExecuteFromNgForm(\n\tform: AbstractControl,\n\toptions?: CanExecuteFormOptions\n): Observable<boolean> {\n\tconst opts: CanExecuteFormOptions = options ?\n\t\t{ ...CAN_EXECUTE_FORM_OPTIONS_DEFAULTS, ...options }\n\t\t: CAN_EXECUTE_FORM_OPTIONS_DEFAULTS;\n\n\tconst pristine$ = opts.dirty\n\t\t? concat(\n\t\t\tdefer(() => of(form.pristine)),\n\t\t\tform.events.pipe(\n\t\t\t\tfilter(x => x instanceof PristineChangeEvent),\n\t\t\t\tmap(x => x.pristine),\n\t\t\t)\n\t\t).pipe(distinctUntilChanged(),)\n\t\t: of(true);\n\n\tconst valid$ = opts.validity\n\t\t? concat(\n\t\t\tdefer(() => of(form.valid)),\n\t\t\tform.events.pipe(\n\t\t\t\tfilter(x => x instanceof StatusChangeEvent),\n\t\t\t\tmap(x => x.status === \"VALID\"),\n\t\t\t)\n\t\t).pipe(distinctUntilChanged(),)\n\t\t: of(true);\n\n\treturn combineLatest([pristine$, valid$]).pipe(\n\t\tmap(([pristine, valid]) => !!(!opts.validity || valid) && !!(!opts.dirty || !pristine)),\n\t\tdistinctUntilChanged(),\n\t);\n}\n\n/** Can executed based on valid/dirty signal inputs. */\nexport function canExecuteFromSignals(\n\tsignals: { valid: Signal<boolean>, dirty: Signal<boolean> },\n\toptions?: CanExecuteFormOptions\n): Signal<boolean> {\n\tconst opts: CanExecuteFormOptions = options ?\n\t\t{ ...CAN_EXECUTE_FORM_OPTIONS_DEFAULTS, ...options }\n\t\t: CAN_EXECUTE_FORM_OPTIONS_DEFAULTS;\n\treturn computed(() => !!(!opts.validity || signals.valid()) && !!(!opts.dirty || signals.dirty()));\n}\n\n\nfunction isAssumedType<T = Record<string, unknown>>(x: unknown): x is Partial<T> {\n\treturn x !== null && typeof x === \"object\";\n}\n","import {\n\tDirective,\n\tOnInit,\n\tElementRef,\n\tRenderer2,\n\tChangeDetectorRef,\n\tinject,\n\teffect,\n\tinput,\n\tInjector,\n\tcomputed,\n\tDestroyRef,\n} from \"@angular/core\";\n\nimport { type CommandOptions, COMMAND_OPTIONS } from \"./command.options\";\nimport { command } from \"./command\";\nimport { isCommand, isCommandCreator } from \"./command.util\";\nimport { CommandCreator, type ICommand } from \"./command.model\";\n\n/**\n * Controls the state of a component in sync with `Command`.\n *\n * @example\n * ### Most common usage\n * ```html\n * <button [ssvCommand]=\"saveCmd\">Save</button>\n * ```\n *\n *\n * ### Usage with options\n * ```html\n * <button [ssvCommand]=\"saveCmd\" [ssvCommandOptions]=\"{executingCssClass: 'in-progress'}\">Save</button>\n * ```\n *\n *\n * ### Usage with params\n * This is useful for collections (loops) or using multiple actions with different args.\n * *NOTE: This will share the `isExecuting` when used with multiple controls.*\n *\n * #### With single param\n *\n * ```html\n * <button [ssvCommand]=\"saveCmd\" [ssvCommandParams]=\"{id: 1}\">Save</button>\n * ```\n * *NOTE: if you have only 1 argument as an array, it should be enclosed within an array e.g. `[['apple', 'banana']]`,\n * else it will spread and you will `arg1: \"apple\", arg2: \"banana\"`*\n *\n * #### With multi params\n * ```html\n * <button [ssvCommand]=\"saveCmd\" [ssvCommandParams]=\"[{id: 1}, 'hello', hero]\">Save</button>\n * ```\n *\n * ### Usage with Command Creator\n * This is useful for collections (loops) or using multiple actions with different args, whilst not sharing `isExecuting`.\n *\n *\n * ```html\n * <button [ssvCommand]=\"{host: this, execute: removeHero$, canExecute: isValid$, params: [hero, 1337, 'xx']}\">Save</button>\n * ```\n *\n */\n\nconst NAME_CAMEL = \"ssvCommand\";\n\n// let nextUniqueId = 0;\n\n@Directive({\n\tselector: `[${NAME_CAMEL}]`,\n\thost: {\n\t\t\"[class]\": \"_hostClasses()\",\n\t\t\"(click)\": \"_handleClick()\",\n\t},\n\texportAs: NAME_CAMEL,\n\tstandalone: true,\n})\nexport class SsvCommand implements OnInit {\n\n\t// readonly id = `${NAME_CAMEL}-${nextUniqueId++}`;\n\treadonly #options = inject(COMMAND_OPTIONS);\n\treadonly #renderer = inject(Renderer2);\n\treadonly #element = inject(ElementRef);\n\treadonly #cdr = inject(ChangeDetectorRef);\n\treadonly #injector = inject(Injector);\n\n\treadonly commandOrCreator = input.required<ICommand | CommandCreator>({\n\t\talias: `ssvCommand`\n\t});\n\treadonly ssvCommandOptions = input<Partial<CommandOptions>>(this.#options);\n\treadonly commandOptions = computed<CommandOptions>(() => {\n\t\tconst value = this.ssvCommandOptions();\n\t\tif (value === this.#options) {\n\t\t\treturn this.#options;\n\t\t}\n\t\treturn {\n\t\t\t...this.#options,\n\t\t\t...value,\n\t\t};\n\t});\n\treadonly ssvCommandParams = input<unknown | unknown[]>(undefined);\n\treadonly commandParams = computed<unknown | unknown[]>(() => this.ssvCommandParams() || this.creatorParams);\n\treadonly _hostClasses = computed(() => [\"ssv-command\", this.#executingClass()]);\n\treadonly #executingClass = computed(() => this._command.$isExecuting() ? this.commandOptions().executingCssClass : \"\");\n\n\tprivate creatorParams: unknown | unknown[] = [];\n\n\tget command(): ICommand { return this._command; }\n\n\tprivate _command!: ICommand;\n\n\tconstructor() {\n\t\tconst destroyRef = inject(DestroyRef);\n\t\tdestroyRef.onDestroy(() => {\n\t\t\tthis._command?.unsubscribe();\n\t\t});\n\t\teffect(() => {\n\t\t\tconst canExecute = this._command.$canExecute();\n\t\t\tthis.trySetDisabled(!canExecute);\n\t\t\t// console.log(\"[ssvCommand::canExecute$]\", { canExecute: x });\n\t\t\tthis.#cdr.markForCheck();\n\t\t});\n\t}\n\n\tngOnInit(): void {\n\t\tconst commandOrCreator = this.commandOrCreator();\n\t\t// console.log(\"[ssvCommand::init]\", this.#options);\n\t\tif (isCommand(commandOrCreator)) {\n\t\t\tthis._command = commandOrCreator;\n\t\t} else if (isCommandCreator(commandOrCreator)) {\n\t\t\tconst isAsync = commandOrCreator.isAsync || commandOrCreator.isAsync === undefined;\n\t\t\tthis.creatorParams = commandOrCreator.params;\n\n\t\t\t// todo: find something like this for ivy (or angular10+)\n\t\t\t// const hostComponent = (this.viewContainer as any)._view.component;\n\n\t\t\tconst execFn = commandOrCreator.execute.bind(commandOrCreator.host);\n\t\t\tconst params = this.commandParams();\n\n\t\t\tconst canExec = commandOrCreator.canExecute instanceof Function\n\t\t\t\t? commandOrCreator.canExecute.bind(commandOrCreator.host, params)()\n\t\t\t\t: commandOrCreator.canExecute;\n\n\t\t\t// console.log(\"[ssvCommand::init] command creator\", {\n\t\t\t// \tfirstParam: params ? params[0] : null,\n\t\t\t// \tparams\n\t\t\t// });\n\n\t\t\tthis._command = command(execFn, canExec, { isAsync, injector: this.#injector });\n\t\t} else {\n\t\t\tthrow new Error(`${NAME_CAMEL}: [${NAME_CAMEL}] is not defined properly!`);\n\t\t}\n\n\t\tthis._command.subscribe();\n\t}\n\n\t_handleClick(): void {\n\t\tconst commandParams = this.commandParams();\n\t\t// console.log(\"[ssvCommand::onClick]\", commandParams);\n\t\tif (Array.isArray(commandParams)) {\n\t\t\tthis._command.execute(...commandParams);\n\t\t} else {\n\t\t\tthis._command.execute(commandParams);\n\t\t}\n\t}\n\n\tprivate trySetDisabled(disabled: boolean) {\n\t\tif (this.commandOptions().handleDisabled) {\n\t\t\t// console.warn(\">>>> disabled\", { id: this.id, disabled });\n\t\t\tthis.#renderer.setProperty(this.#element.nativeElement, \"disabled\", disabled);\n\t\t}\n\t}\n\n}\n\n","import { Directive, OnInit, inject, Injector, DestroyRef, input } from \"@angular/core\";\n\nimport type { ICommand, CommandCreator, CanExecute } from \"./command.model\";\nimport { isCommandCreator } from \"./command.util\";\nimport { command } from \"./command\";\n\nconst NAME_CAMEL = \"ssvCommandRef\";\n\n/**\n * Command creator ref, directive which allows creating Command in the template\n * and associate it to a command (in order to share executions).\n * @example\n * ### Most common usage\n * ```html\n * <div #actionCmd=\"ssvCommandRef\" [ssvCommandRef]=\"{host: this, execute: removeHero$, canExecute: isValid$}\">\n * <button [ssvCommand]=\"actionCmd.command\" [ssvCommandParams]=\"hero\">\n * Remove\n * </button>\n * <button [ssvCommand]=\"actionCmd.command\" [ssvCommandParams]=\"hero\">\n * Remove\n * </button>\n * </div>\n * ```\n *\n */\n@Directive({\n\tselector: `[${NAME_CAMEL}]`,\n\texportAs: NAME_CAMEL,\n\tstandalone: true,\n})\nexport class SsvCommandRef implements OnInit {\n\n\treadonly #injector = inject(Injector);\n\n\treadonly commandCreator = input.required<CommandCreator>({\n\t\talias: `ssvCommandRef`\n\t});\n\n\tget command(): ICommand { return this._command; }\n\tprivate _command!: ICommand;\n\n\tconstructor() {\n\t\tconst destroyRef = inject(DestroyRef);\n\t\tdestroyRef.onDestroy(() => {\n\t\t\tthis._command?.unsubscribe();\n\t\t});\n\t}\n\n\tngOnInit(): void {\n\t\tif (isCommandCreator(this.commandCreator())) {\n\t\t\tconst commandCreator = this.commandCreator();\n\t\t\tconst isAsync = commandCreator.isAsync || commandCreator.isAsync === undefined;\n\n\t\t\tconst execFn = commandCreator.execute.bind(commandCreator.host);\n\n\t\t\tthis._command = command(execFn, commandCreator.canExecute as CanExecute, { isAsync, injector: this.#injector });\n\t\t} else {\n\t\t\tthrow new Error(`${NAME_CAMEL}: [${NAME_CAMEL}] is not defined properly!`);\n\t\t}\n\t}\n\n}\n","import { NgModule } from \"@angular/core\";\n\nimport { SsvCommand } from \"./command.directive\";\nimport { SsvCommandRef } from \"./command-ref.directive\";\n\nconst EXPORTED_IMPORTS = [\n\tSsvCommand,\n\tSsvCommandRef\n];\n\n/** @deprecated Use standalone instead. */\n@NgModule({\n\timports: [EXPORTED_IMPORTS],\n\texports: [EXPORTED_IMPORTS]\n})\nexport class SsvCommandModule {\n\n}\n","export const VERSION = \"4.0.0\";\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["NAME_CAMEL"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ssv-ngx.command.mjs","sources":["../../../../libs/ngx.command/src/command.options.ts","../../../../libs/ngx.command/src/command.ts","../../../../libs/ngx.command/src/command.util.ts","../../../../libs/ngx.command/src/command.directive.ts","../../../../libs/ngx.command/src/command-ref.directive.ts","../../../../libs/ngx.command/src/command.module.ts","../../../../libs/ngx.command/src/version.ts","../../../../libs/ngx.command/src/ssv-ngx.command.ts"],"sourcesContent":["import { InjectionToken, type Provider } from \"@angular/core\";\n\nexport interface CommandOptions {\n\t/**\n\t * Css Class which gets added/removed on the Command element's host while Command `isExecuting$`.\n\t */\n\texecutingCssClass: string;\n\n\t/** Determines whether the disabled will be handled by the directive or not.\n\t * Disable handled by directive's doesn't always play nice when used with other component/pipe/directive and they also handle disabled.\n\t * This disables the handling manually and need to pass explicitly `[disabled]=\"!saveCmd.canExecute\"`.\n\t */\n\thandleDisabled: boolean;\n}\n\nconst DEFAULT_OPTIONS = Object.freeze<CommandOptions>({\n\texecutingCssClass: \"executing\",\n\thandleDisabled: true,\n});\n\nexport const COMMAND_OPTIONS = new InjectionToken<CommandOptions>(\"SSV_COMMAND_OPTIONS\", {\n\tfactory: () => DEFAULT_OPTIONS,\n});\n\nexport function provideSsvCommandOptions(\n\toptions: Partial<CommandOptions> | ((defaults: Readonly<CommandOptions>) => Partial<CommandOptions>)\n): Provider[] {\n\treturn [\n\t\t{\n\t\t\tprovide: COMMAND_OPTIONS,\n\t\t\tuseFactory: () => {\n\t\t\t\tlet opts = typeof options === \"function\" ? options(DEFAULT_OPTIONS) : options;\n\t\t\t\topts = opts\n\t\t\t\t\t? {\n\t\t\t\t\t\t...DEFAULT_OPTIONS,\n\t\t\t\t\t\t...opts,\n\t\t\t\t\t}\n\t\t\t\t\t: DEFAULT_OPTIONS;\n\t\t\t\treturn opts;\n\t\t\t},\n\t\t},\n\t];\n}\n","\nimport { isObservable, lastValueFrom } from \"rxjs\";\nimport { toSignal } from \"@angular/core/rxjs-interop\";\nimport type { CanExecute, ExecuteFn, ExecuteReturnType, ICommand } from \"./command.model\";\nimport { assertInInjectionContext, computed, inject, Injector, isSignal, signal, type Signal } from \"@angular/core\";\n\nexport interface CommandCreateOptions {\n\tinjector?: Injector;\n}\n\n// todo: remove\n/** Creates an async {@link Command}. Must be used within an injection context.\n * @deprecated Use {@link command} instead, as it handles both sync and async execute functions.\n */\nexport const commandAsync = command;\n\n/** Creates a {@link Command}. Must be used within an injection context (or the injector must be provided in the options). */\nexport function command<TExecute extends ExecuteFn>(\n\texecute: TExecute,\n\tcanExecute?: CanExecute,\n\topts?: CommandCreateOptions,\n): Command<TExecute> {\n\tif (!opts?.injector) {\n\t\tassertInInjectionContext(command);\n\t}\n\tconst injector = opts?.injector ?? inject(Injector);\n\tconst cmd = new Command(execute, canExecute, injector);\n\treturn cmd;\n}\n\n/**\n * Command object used to encapsulate information which is needed to perform an action.\n */\nexport class Command<TExecute extends ExecuteFn = ExecuteFn> implements ICommand<TExecute> {\n\n\tget isExecuting(): boolean { return this.$isExecuting(); }\n\n\tget canExecute(): boolean { return this.$canExecute(); }\n\n\treadonly $isExecuting = signal(false);\n\treadonly $canExecute = computed(() => !this.$isExecuting() && this.#canExecute());\n\n\treadonly #canExecute: Signal<boolean>;\n\n\t/**\n\t * Creates an instance of Command.\n\t *\n\t * @param execute Execute function to invoke.\n\t * @param canExecute Observable which determines whether it can execute or not.\n\t * @deprecated Use {@link command} or {@link commandAsync} instead for creating instances.\n\t */\n\tconstructor(\n\t\tprivate readonly _execute: TExecute,\n\t\tcanExecute?: CanExecute,\n\t\tinjector?: Injector,\n\t) {\n\t\tthis.#canExecute = this.#buildCanExecuteSignal(canExecute, injector);\n\t}\n\n\t/** Execute function to invoke. Returns Promise if the execute function returns Observable, otherwise returns the original type. */\n\texecute(...args: Parameters<TExecute>): ExecuteReturnType<TExecute> {\n\t\tif (!this.$canExecute()) {\n\t\t\tthrow new Error(\"Command cannot execute in its current state.\");\n\t\t\t// return Promise.reject() as ReturnType<TExecute>;\n\t\t}\n\t\tthis.$isExecuting.set(true);\n\n\t\t// console.warn(\"[command::execute]\", args);\n\n\t\ttry {\n\t\t\tconst result = args.length > 0 ? this._execute(...args) : this._execute();\n\n\t\t\tif (isObservable(result)) {\n\t\t\t\t// Convert observable to promise using lastValueFrom\n\t\t\t\t// This ensures fire-and-forget execution without requiring manual subscription\n\t\t\t\t// Use defaultValue to handle empty observables (those that complete without emitting)\n\t\t\t\tconst promise = lastValueFrom(result, { defaultValue: undefined })\n\t\t\t\t\t.finally(() => this.$isExecuting.set(false));\n\t\t\t\treturn promise as ExecuteReturnType<TExecute>;\n\t\t\t} else if (result instanceof Promise) {\n\t\t\t\t// Return promise with proper cleanup\n\t\t\t\treturn result\n\t\t\t\t\t.finally(() => this.$isExecuting.set(false)) as ExecuteReturnType<TExecute>;\n\t\t\t}\n\t\t\t// Sync execution\n\t\t\tthis.$isExecuting.set(false);\n\t\t\treturn result as ExecuteReturnType<TExecute>;\n\t\t} catch (err) {\n\t\t\tthis.$isExecuting.set(false);\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\t#buildCanExecuteSignal(canExecute?: CanExecute, injector?: Injector): Signal<boolean> {\n\t\tif (canExecute === undefined) {\n\t\t\treturn computed(() => true);\n\t\t}\n\t\tif (isSignal(canExecute)) {\n\t\t\treturn canExecute;\n\t\t}\n\t\tif (typeof canExecute === \"function\") {\n\t\t\treturn computed(canExecute);\n\t\t}\n\t\tif (typeof canExecute === \"boolean\") {\n\t\t\treturn computed(() => canExecute);\n\t\t}\n\t\treturn toSignal(canExecute, { initialValue: false, injector });\n\t}\n\n}\n","import { type AbstractControl, PristineChangeEvent, StatusChangeEvent } from \"@angular/forms\";\nimport { Observable, map, distinctUntilChanged, filter, combineLatest, of, defer, concat } from \"rxjs\";\n\nimport type { CommandCreator, ICommand } from \"./command.model\";\nimport { Command } from \"./command\";\nimport { type Signal, computed } from \"@angular/core\";\n\n/** Determines whether the arg object is of type `Command`. */\nexport function isCommand<T extends ICommand>(arg: unknown | T): arg is T {\n\treturn arg instanceof Command;\n}\n\n/** Determines whether the arg object is of type `CommandCreator`. */\nexport function isCommandCreator<T extends CommandCreator>(arg: unknown | T): arg is T {\n\tif (arg instanceof Command) {\n\t\treturn false;\n\t} else if (isAssumedType<T>(arg) && arg.execute && arg.host) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nexport interface CanExecuteFormOptions {\n\t/** Determines whether to check for validity. (defaults: true) */\n\tvalidity?: boolean;\n\n\t/** Determines whether to check whether UI has been touched. (defaults: true) */\n\tdirty?: boolean;\n}\n\nconst CAN_EXECUTE_FORM_OPTIONS_DEFAULTS = Object.freeze<CanExecuteFormOptions>({\n\tvalidity: true,\n\tdirty: true,\n})\n\n/** Get can execute from form validity/pristine as an observable. */\nexport function canExecuteFromNgForm(\n\tform: AbstractControl,\n\toptions?: CanExecuteFormOptions\n): Observable<boolean> {\n\tconst opts: CanExecuteFormOptions = options ?\n\t\t{ ...CAN_EXECUTE_FORM_OPTIONS_DEFAULTS, ...options }\n\t\t: CAN_EXECUTE_FORM_OPTIONS_DEFAULTS;\n\n\tconst pristine$ = opts.dirty\n\t\t? concat(\n\t\t\tdefer(() => of(form.pristine)),\n\t\t\tform.events.pipe(\n\t\t\t\tfilter(x => x instanceof PristineChangeEvent),\n\t\t\t\tmap(x => x.pristine),\n\t\t\t)\n\t\t).pipe(distinctUntilChanged(),)\n\t\t: of(true);\n\n\tconst valid$ = opts.validity\n\t\t? concat(\n\t\t\tdefer(() => of(form.valid)),\n\t\t\tform.events.pipe(\n\t\t\t\tfilter(x => x instanceof StatusChangeEvent),\n\t\t\t\tmap(x => x.status === \"VALID\"),\n\t\t\t)\n\t\t).pipe(distinctUntilChanged(),)\n\t\t: of(true);\n\n\treturn combineLatest([pristine$, valid$]).pipe(\n\t\tmap(([pristine, valid]) => !!(!opts.validity || valid) && !!(!opts.dirty || !pristine)),\n\t\tdistinctUntilChanged(),\n\t);\n}\n\n/** Can executed based on valid/dirty signal inputs. */\nexport function canExecuteFromSignals(\n\tsignals: { valid: Signal<boolean>, dirty: Signal<boolean> },\n\toptions?: CanExecuteFormOptions\n): Signal<boolean> {\n\tconst opts: CanExecuteFormOptions = options ?\n\t\t{ ...CAN_EXECUTE_FORM_OPTIONS_DEFAULTS, ...options }\n\t\t: CAN_EXECUTE_FORM_OPTIONS_DEFAULTS;\n\treturn computed(() => !!(!opts.validity || signals.valid()) && !!(!opts.dirty || signals.dirty()));\n}\n\n\nfunction isAssumedType<T = Record<string, unknown>>(x: unknown): x is Partial<T> {\n\treturn x !== null && typeof x === \"object\";\n}\n","import {\n\tDirective,\n\tOnInit,\n\tElementRef,\n\tRenderer2,\n\tChangeDetectorRef,\n\tinject,\n\teffect,\n\tinput,\n\tInjector,\n\tcomputed,\n\tsignal,\n} from \"@angular/core\";\n\nimport { type CommandOptions, COMMAND_OPTIONS } from \"./command.options\";\nimport { command, type Command } from \"./command\";\nimport { isCommand, isCommandCreator } from \"./command.util\";\nimport { CommandCreator, type ICommand, type CanExecute, type ExecuteFn, type CommandParams, type Simplify } from \"./command.model\";\n\n/** Helper type to extract ExecuteFn from ICommand/Command or use ExecuteFn directly */\ntype ExtractExecuteFn<T> = T extends Command<infer TExec>\n\t? TExec\n\t: T extends ICommand<infer TExec>\n\t? TExec\n\t: T extends ExecuteFn\n\t? T\n\t: never;\n\nconst NAME_CAMEL = \"ssvCommand\";\n\n// let nextUniqueId = 0;\n\n/**\n * Controls the state of a component in sync with `Command`.\n *\n * @example\n * ### Most common usage\n * ```html\n * <button [ssvCommand]=\"saveCmd\">Save</button>\n * ```\n *\n *\n * ### Usage with options\n * ```html\n * <button [ssvCommand]=\"saveCmd\" [ssvCommandOptions]=\"{executingCssClass: 'in-progress'}\">Save</button>\n * ```\n *\n *\n * ### Usage with params\n * This is useful for collections (loops) or using multiple actions with different args.\n * *NOTE: This will share the `isExecuting` when used with multiple controls.*\n *\n * #### With single param (direct)\n *\n * ```html\n * <button [ssvCommand]=\"saveCmd\" [ssvCommandParams]=\"hero\">Save</button>\n * ```\n *\n * #### With single param (array)\n *\n * ```html\n * <button [ssvCommand]=\"saveCmd\" [ssvCommandParams]=\"[hero]\">Save</button>\n * ```\n *\n * *NOTE: if you have only 1 argument as an array, it should be enclosed within an array e.g. `[['apple', 'banana']]`,\n * else it will spread and you will get `arg1: \"apple\", arg2: \"banana\"`*\n *\n * #### With multi params\n * ```html\n * <button [ssvCommand]=\"saveCmd\" [ssvCommandParams]=\"[{id: 1}, 'hello', hero]\">Save</button>\n * ```\n *\n * ### Usage with Command Creator\n * This is useful for collections (loops) or using multiple actions with different args, whilst not sharing `isExecuting`.\n *\n *\n * ```html\n * <button [ssvCommand]=\"{host: this, execute: removeHero$, canExecute: isValid$, params: [hero, 1337, 'xx']}\">Save</button>\n * ```\n *\n */\n@Directive({\n\tselector: `[${NAME_CAMEL}]`,\n\thost: {\n\t\t\"[class]\": \"_hostClasses()\",\n\t\t\"(click)\": \"_handleClick()\",\n\t},\n\t// todo: handle keydown/enter?\n\texportAs: NAME_CAMEL,\n\tstandalone: true,\n})\nexport class SsvCommand<T extends ICommand | ExecuteFn = ExecuteFn> implements OnInit {\n\n\t// readonly id = `${NAME_CAMEL}-${nextUniqueId++}`;\n\treadonly #options = inject(COMMAND_OPTIONS);\n\treadonly #renderer = inject(Renderer2);\n\treadonly #element = inject(ElementRef);\n\treadonly #cdr = inject(ChangeDetectorRef);\n\treadonly #injector = inject(Injector);\n\n\treadonly commandOrCreator = input.required<T extends ICommand ? T : (ICommand<ExtractExecuteFn<T>> | CommandCreator<ExtractExecuteFn<T>>)>({\n\t\talias: `ssvCommand`\n\t});\n\treadonly ssvCommandOptions = input<Partial<CommandOptions>>(this.#options);\n\treadonly commandOptions = computed<CommandOptions>(() => {\n\t\tconst value = this.ssvCommandOptions();\n\t\tif (value === this.#options) {\n\t\t\treturn this.#options;\n\t\t}\n\t\treturn {\n\t\t\t...this.#options,\n\t\t\t...value,\n\t\t};\n\t});\n\treadonly ssvCommandParams = input<Simplify<CommandParams<ExtractExecuteFn<T>>>>();\n\treadonly commandParams = computed(() => {\n\t\tconst params = this.ssvCommandParams();\n\t\tif (params === undefined) {\n\t\t\treturn this.#creatorParams();\n\t\t}\n\t\t// Normalize single param to array format for consistent handling\n\t\treturn this.#normalizeParams(params as CommandParams<ExtractExecuteFn<T>>);\n\t});\n\treadonly _hostClasses = computed(() => [\"ssv-command\", this.#executingClass()]);\n\treadonly #executingClass = computed(() => this.#command().$isExecuting() ? this.commandOptions().executingCssClass : \"\");\n\n\treadonly #creatorParams = signal<Parameters<ExtractExecuteFn<T>> | undefined>(undefined);\n\n\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\treadonly #command = signal<ICommand<ExtractExecuteFn<T>>>(undefined!);\n\treadonly command = this.#command.asReadonly();\n\n\tconstructor() {\n\t\teffect(() => {\n\t\t\tconst canExecute = this.#command().$canExecute();\n\t\t\tthis.trySetDisabled(!canExecute);\n\t\t\t// console.log(\"[ssvCommand::canExecute$]\", { canExecute: x });\n\t\t\tthis.#cdr.markForCheck();\n\t\t});\n\t}\n\n\t// todo: afterNextRender\n\tngOnInit(): void {\n\t\tconst commandOrCreator = this.commandOrCreator();\n\t\t// console.log(\"[ssvCommand::init]\", this.#options);\n\t\tif (isCommand(commandOrCreator)) {\n\t\t\tthis.#command.set(commandOrCreator);\n\t\t} else if (isCommandCreator(commandOrCreator)) {\n\t\t\tthis.#creatorParams.set(this.#normalizeParams(commandOrCreator.params as CommandParams<ExtractExecuteFn<T>>));\n\n\t\t\t// todo: find something like this for ivy (or angular10+)\n\t\t\t// const hostComponent = (this.viewContainer as any)._view.component;\n\n\t\t\tconst execFn = commandOrCreator.execute.bind(commandOrCreator.host) as ExtractExecuteFn<T>;\n\t\t\tconst params = this.commandParams();\n\n\t\t\tlet canExec: CanExecute | undefined;\n\t\t\tif (commandOrCreator.canExecute instanceof Function) {\n\t\t\t\tconst boundFn = commandOrCreator.canExecute.bind(commandOrCreator.host);\n\t\t\t\tconst result = Array.isArray(params) ? boundFn(...params) : boundFn();\n\t\t\t\tcanExec = result as CanExecute;\n\t\t\t} else {\n\t\t\t\tcanExec = commandOrCreator.canExecute;\n\t\t\t}\n\n\t\t\t// console.log(\"[ssvCommand::init] command creator\", {\n\t\t\t// \tfirstParam: params ? params[0] : null,\n\t\t\t// \tparams\n\t\t\t// });\n\t\t\tconst cmd = command(execFn, canExec, { injector: this.#injector });\n\t\t\tthis.#command.set(cmd);\n\t\t} else {\n\t\t\tthrow new Error(`${NAME_CAMEL}: [${NAME_CAMEL}] is not defined properly!`);\n\t\t}\n\t}\n\n\t_handleClick(): void {\n\t\tconst commandParams = this.commandParams();\n\t\t// console.log(\"[ssvCommand::onClick]\", commandParams);\n\t\tif (Array.isArray(commandParams)) {\n\t\t\tthis.#command().execute(...commandParams);\n\t\t} else {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t(this.#command().execute as any)();\n\t\t}\n\t}\n\n\tprivate trySetDisabled(disabled: boolean) {\n\t\tif (this.commandOptions().handleDisabled) {\n\t\t\t// console.warn(\">>>> disabled\", { id: this.id, disabled });\n\t\t\tthis.#renderer.setProperty(this.#element.nativeElement, \"disabled\", disabled);\n\t\t}\n\t}\n\n\t/** Normalizes params to array format for consistent execution */\n\t#normalizeParams(params: CommandParams<ExtractExecuteFn<T>>): Parameters<ExtractExecuteFn<T>> | undefined {\n\t\t// If params is already an array, return as-is\n\t\tif (Array.isArray(params)) {\n\t\t\treturn params as Parameters<ExtractExecuteFn<T>>;\n\t\t}\n\t\t// Single non-array param - wrap it\n\t\treturn [params] as Parameters<ExtractExecuteFn<T>>;\n\t}\n\n}\n","import { Directive, OnInit, inject, Injector, input, signal } from \"@angular/core\";\n\nimport type { ICommand, CommandCreator, CanExecute, ExecuteFn } from \"./command.model\";\nimport { isCommandCreator } from \"./command.util\";\nimport { command } from \"./command\";\n\nconst NAME_CAMEL = \"ssvCommandRef\";\n\n/**\n * Command creator ref, directive which allows creating Command in the template\n * and associate it to a command (in order to share executions).\n * @example\n * ### Most common usage\n * ```html\n * <div #actionCmd=\"ssvCommandRef\" [ssvCommandRef]=\"{host: this, execute: removeHero$, canExecute: isValid$}\">\n * <button [ssvCommand]=\"actionCmd.command()\" [ssvCommandParams]=\"[hero]\">\n * Remove\n * </button>\n * <button [ssvCommand]=\"actionCmd.command()\" [ssvCommandParams]=\"[hero]\">\n * Remove\n * </button>\n * </div>\n * ```\n *\n */\n@Directive({\n\tselector: `[${NAME_CAMEL}]`,\n\texportAs: NAME_CAMEL,\n\tstandalone: true,\n})\nexport class SsvCommandRef<TExecute extends ExecuteFn = ExecuteFn> implements OnInit {\n\n\treadonly #injector = inject(Injector);\n\n\treadonly commandCreator = input.required<CommandCreator<TExecute>>({\n\t\talias: `ssvCommandRef`\n\t});\n\n\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\treadonly #command = signal<ICommand<TExecute>>(undefined!);\n\treadonly command = this.#command.asReadonly();\n\n\t// todo: use afterNextRender\n\tngOnInit(): void {\n\t\tconst commandOrCreator = this.commandCreator();\n\t\tif (isCommandCreator(commandOrCreator)) {\n\t\t\tconst commandCreator = commandOrCreator;\n\n\t\t\tconst execFn = commandCreator.execute.bind(commandCreator.host) as TExecute;\n\n\t\t\tconst cmd = command(execFn, commandCreator.canExecute as CanExecute, { injector: this.#injector });\n\t\t\tthis.#command.set(cmd);\n\t\t} else {\n\t\t\tthrow new Error(`${NAME_CAMEL}: [${NAME_CAMEL}] is not defined properly!`);\n\t\t}\n\t}\n\n}\n","import { NgModule } from \"@angular/core\";\n\nimport { SsvCommand } from \"./command.directive\";\nimport { SsvCommandRef } from \"./command-ref.directive\";\n\nconst EXPORTED_IMPORTS = [\n\tSsvCommand,\n\tSsvCommandRef\n];\n\n/** @deprecated Use standalone instead. */\n@NgModule({\n\timports: [EXPORTED_IMPORTS],\n\texports: [EXPORTED_IMPORTS]\n})\nexport class SsvCommandModule {\n\n}\n","export const VERSION = \"5.0.0-dev.113\";\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["NAME_CAMEL"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ssv/ngx.command",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0-dev.113",
|
|
4
4
|
"versionSuffix": "",
|
|
5
5
|
"description": "Command pattern implementation for angular. Command used to encapsulate information which is needed to perform an action.",
|
|
6
6
|
"keywords": [
|
|
@@ -19,9 +19,6 @@
|
|
|
19
19
|
"type": "git",
|
|
20
20
|
"url": "https://github.com/sketch7/ssv.ngx.git"
|
|
21
21
|
},
|
|
22
|
-
"dependencies": {
|
|
23
|
-
"tslib": "^2.3.0"
|
|
24
|
-
},
|
|
25
22
|
"peerDependencies": {
|
|
26
23
|
"@angular/core": ">=17.0.0",
|
|
27
24
|
"@angular/forms": ">=17.0.0",
|
|
@@ -29,14 +26,17 @@
|
|
|
29
26
|
},
|
|
30
27
|
"sideEffects": false,
|
|
31
28
|
"module": "fesm2022/ssv-ngx.command.mjs",
|
|
32
|
-
"typings": "
|
|
29
|
+
"typings": "types/ssv-ngx.command.d.ts",
|
|
33
30
|
"exports": {
|
|
34
31
|
"./package.json": {
|
|
35
32
|
"default": "./package.json"
|
|
36
33
|
},
|
|
37
34
|
".": {
|
|
38
|
-
"types": "./
|
|
35
|
+
"types": "./types/ssv-ngx.command.d.ts",
|
|
39
36
|
"default": "./fesm2022/ssv-ngx.command.mjs"
|
|
40
37
|
}
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"tslib": "^2.3.0"
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { Provider, InjectionToken, Signal, Injector, OnInit } from '@angular/core';
|
|
3
|
+
import { Observable } from 'rxjs';
|
|
4
|
+
import { AbstractControl } from '@angular/forms';
|
|
5
|
+
|
|
6
|
+
interface CommandOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Css Class which gets added/removed on the Command element's host while Command `isExecuting$`.
|
|
9
|
+
*/
|
|
10
|
+
executingCssClass: string;
|
|
11
|
+
/** Determines whether the disabled will be handled by the directive or not.
|
|
12
|
+
* Disable handled by directive's doesn't always play nice when used with other component/pipe/directive and they also handle disabled.
|
|
13
|
+
* This disables the handling manually and need to pass explicitly `[disabled]="!saveCmd.canExecute"`.
|
|
14
|
+
*/
|
|
15
|
+
handleDisabled: boolean;
|
|
16
|
+
}
|
|
17
|
+
declare const COMMAND_OPTIONS: InjectionToken<CommandOptions>;
|
|
18
|
+
declare function provideSsvCommandOptions(options: Partial<CommandOptions> | ((defaults: Readonly<CommandOptions>) => Partial<CommandOptions>)): Provider[];
|
|
19
|
+
|
|
20
|
+
/** Type that represents a sync or async value. */
|
|
21
|
+
type MaybeAsync<T> = T | Observable<T> | Promise<T>;
|
|
22
|
+
type SignalLike<T> = (() => T);
|
|
23
|
+
/** Converts Observable<T> to Promise<T>, leaves other types unchanged */
|
|
24
|
+
type ConvertObservableToPromise<T> = T extends Observable<infer U> ? Promise<U> : T;
|
|
25
|
+
/** Return type of Execute function, converting `Observable` to `Promise` if needed */
|
|
26
|
+
type ExecuteReturnType<TExecute extends ExecuteFn> = ConvertObservableToPromise<ReturnType<TExecute>>;
|
|
27
|
+
type ExecuteFn<TArgs extends any[] = any[], TReturn = unknown> = (...args: TArgs) => MaybeAsync<TReturn>;
|
|
28
|
+
type CanExecute = SignalLike<boolean> | Signal<boolean> | Observable<boolean> | boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Type for command parameters that allows:
|
|
31
|
+
* - Single parameter passed directly (not in array)
|
|
32
|
+
* - Multiple parameters as tuple array
|
|
33
|
+
* - Single array parameter wrapped in array to prevent spreading
|
|
34
|
+
*/
|
|
35
|
+
type CommandParams<TExec extends ExecuteFn> = Parameters<TExec> extends [infer Single] ? Single | [Single] : Parameters<TExec> extends [] ? never : Parameters<TExec>;
|
|
36
|
+
/** `command` input type convenience.
|
|
37
|
+
* @example
|
|
38
|
+
* For a command with a single parameter:
|
|
39
|
+
* ```ts
|
|
40
|
+
* readonly myCmd = input.required<CommandInput<MyType>>();
|
|
41
|
+
* ```
|
|
42
|
+
* For a command with multiple parameters:
|
|
43
|
+
* ```ts
|
|
44
|
+
* readonly myCmd = input.required<CommandInput<[param1: string, param2: number]>>();
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
type CommandInput<TArgs = unknown, R = unknown> = TArgs extends readonly [unknown, ...unknown[]] ? Command<(...args: TArgs) => R> : TArgs extends readonly [infer Single] ? Command<(arg: Single) => R> : Command<(arg: TArgs) => R>;
|
|
48
|
+
interface ICommand<TExecute extends ExecuteFn = ExecuteFn> {
|
|
49
|
+
/** Determines whether the command is currently executing, as a snapshot value.
|
|
50
|
+
* @deprecated Use {@link $isExecuting} signal instead.
|
|
51
|
+
*/
|
|
52
|
+
readonly isExecuting: boolean;
|
|
53
|
+
/** Determines whether the command is currently executing, as a signal. */
|
|
54
|
+
readonly $isExecuting: Signal<boolean>;
|
|
55
|
+
/** Determines whether the command can execute or not, as a snapshot value.
|
|
56
|
+
* @deprecated Use {@link $canExecute} signal instead.
|
|
57
|
+
*/
|
|
58
|
+
readonly canExecute: boolean;
|
|
59
|
+
/** Determines whether the command can execute or not, as a signal. */
|
|
60
|
+
readonly $canExecute: Signal<boolean>;
|
|
61
|
+
/** Execute function to invoke. Returns Promise if the execute function returns Observable, otherwise returns the original type. */
|
|
62
|
+
execute(...args: Parameters<TExecute>): ExecuteReturnType<TExecute>;
|
|
63
|
+
}
|
|
64
|
+
interface CommandCreator<TExecute extends ExecuteFn = ExecuteFn> {
|
|
65
|
+
/** Execute function to invoke. */
|
|
66
|
+
execute: TExecute;
|
|
67
|
+
/** Determines whether the command can execute or not. Can be a signal, observable, or function. */
|
|
68
|
+
canExecute?: CanExecute | ((...args: Parameters<TExecute>) => CanExecute);
|
|
69
|
+
/** Parameters to pass to the execute function. */
|
|
70
|
+
params?: CommandParams<TExecute>;
|
|
71
|
+
/** Host context for binding the execute function. */
|
|
72
|
+
host: unknown;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface CommandCreateOptions {
|
|
76
|
+
injector?: Injector;
|
|
77
|
+
}
|
|
78
|
+
/** Creates an async {@link Command}. Must be used within an injection context.
|
|
79
|
+
* @deprecated Use {@link command} instead, as it handles both sync and async execute functions.
|
|
80
|
+
*/
|
|
81
|
+
declare const commandAsync: typeof command;
|
|
82
|
+
/** Creates a {@link Command}. Must be used within an injection context (or the injector must be provided in the options). */
|
|
83
|
+
declare function command<TExecute extends ExecuteFn>(execute: TExecute, canExecute?: CanExecute, opts?: CommandCreateOptions): Command<TExecute>;
|
|
84
|
+
/**
|
|
85
|
+
* Command object used to encapsulate information which is needed to perform an action.
|
|
86
|
+
*/
|
|
87
|
+
declare class Command<TExecute extends ExecuteFn = ExecuteFn> implements ICommand<TExecute> {
|
|
88
|
+
#private;
|
|
89
|
+
private readonly _execute;
|
|
90
|
+
get isExecuting(): boolean;
|
|
91
|
+
get canExecute(): boolean;
|
|
92
|
+
readonly $isExecuting: _angular_core.WritableSignal<boolean>;
|
|
93
|
+
readonly $canExecute: Signal<boolean>;
|
|
94
|
+
/**
|
|
95
|
+
* Creates an instance of Command.
|
|
96
|
+
*
|
|
97
|
+
* @param execute Execute function to invoke.
|
|
98
|
+
* @param canExecute Observable which determines whether it can execute or not.
|
|
99
|
+
* @deprecated Use {@link command} or {@link commandAsync} instead for creating instances.
|
|
100
|
+
*/
|
|
101
|
+
constructor(_execute: TExecute, canExecute?: CanExecute, injector?: Injector);
|
|
102
|
+
/** Execute function to invoke. Returns Promise if the execute function returns Observable, otherwise returns the original type. */
|
|
103
|
+
execute(...args: Parameters<TExecute>): ExecuteReturnType<TExecute>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Helper type to extract ExecuteFn from ICommand/Command or use ExecuteFn directly */
|
|
107
|
+
type ExtractExecuteFn<T> = T extends Command<infer TExec> ? TExec : T extends ICommand<infer TExec> ? TExec : T extends ExecuteFn ? T : never;
|
|
108
|
+
/**
|
|
109
|
+
* Controls the state of a component in sync with `Command`.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ### Most common usage
|
|
113
|
+
* ```html
|
|
114
|
+
* <button [ssvCommand]="saveCmd">Save</button>
|
|
115
|
+
* ```
|
|
116
|
+
*
|
|
117
|
+
*
|
|
118
|
+
* ### Usage with options
|
|
119
|
+
* ```html
|
|
120
|
+
* <button [ssvCommand]="saveCmd" [ssvCommandOptions]="{executingCssClass: 'in-progress'}">Save</button>
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
*
|
|
124
|
+
* ### Usage with params
|
|
125
|
+
* This is useful for collections (loops) or using multiple actions with different args.
|
|
126
|
+
* *NOTE: This will share the `isExecuting` when used with multiple controls.*
|
|
127
|
+
*
|
|
128
|
+
* #### With single param (direct)
|
|
129
|
+
*
|
|
130
|
+
* ```html
|
|
131
|
+
* <button [ssvCommand]="saveCmd" [ssvCommandParams]="hero">Save</button>
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* #### With single param (array)
|
|
135
|
+
*
|
|
136
|
+
* ```html
|
|
137
|
+
* <button [ssvCommand]="saveCmd" [ssvCommandParams]="[hero]">Save</button>
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* *NOTE: if you have only 1 argument as an array, it should be enclosed within an array e.g. `[['apple', 'banana']]`,
|
|
141
|
+
* else it will spread and you will get `arg1: "apple", arg2: "banana"`*
|
|
142
|
+
*
|
|
143
|
+
* #### With multi params
|
|
144
|
+
* ```html
|
|
145
|
+
* <button [ssvCommand]="saveCmd" [ssvCommandParams]="[{id: 1}, 'hello', hero]">Save</button>
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
148
|
+
* ### Usage with Command Creator
|
|
149
|
+
* This is useful for collections (loops) or using multiple actions with different args, whilst not sharing `isExecuting`.
|
|
150
|
+
*
|
|
151
|
+
*
|
|
152
|
+
* ```html
|
|
153
|
+
* <button [ssvCommand]="{host: this, execute: removeHero$, canExecute: isValid$, params: [hero, 1337, 'xx']}">Save</button>
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
*/
|
|
157
|
+
declare class SsvCommand<T extends ICommand | ExecuteFn = ExecuteFn> implements OnInit {
|
|
158
|
+
#private;
|
|
159
|
+
readonly commandOrCreator: _angular_core.InputSignal<T extends ICommand<ExecuteFn<any[], unknown>> ? T : ICommand<ExtractExecuteFn<T>> | CommandCreator<ExtractExecuteFn<T>>>;
|
|
160
|
+
readonly ssvCommandOptions: _angular_core.InputSignal<Partial<CommandOptions>>;
|
|
161
|
+
readonly commandOptions: _angular_core.Signal<CommandOptions>;
|
|
162
|
+
readonly ssvCommandParams: _angular_core.InputSignal<(CommandParams<ExtractExecuteFn<T>> extends infer T_1 ? { [KeyType in keyof T_1]: T_1[KeyType]; } : never) | undefined>;
|
|
163
|
+
readonly commandParams: _angular_core.Signal<Parameters<ExtractExecuteFn<T>> | undefined>;
|
|
164
|
+
readonly _hostClasses: _angular_core.Signal<string[]>;
|
|
165
|
+
readonly command: _angular_core.Signal<ICommand<ExtractExecuteFn<T>>>;
|
|
166
|
+
constructor();
|
|
167
|
+
ngOnInit(): void;
|
|
168
|
+
_handleClick(): void;
|
|
169
|
+
private trySetDisabled;
|
|
170
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SsvCommand<any>, never>;
|
|
171
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SsvCommand<any>, "[ssvCommand]", ["ssvCommand"], { "commandOrCreator": { "alias": "ssvCommand"; "required": true; "isSignal": true; }; "ssvCommandOptions": { "alias": "ssvCommandOptions"; "required": false; "isSignal": true; }; "ssvCommandParams": { "alias": "ssvCommandParams"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Command creator ref, directive which allows creating Command in the template
|
|
176
|
+
* and associate it to a command (in order to share executions).
|
|
177
|
+
* @example
|
|
178
|
+
* ### Most common usage
|
|
179
|
+
* ```html
|
|
180
|
+
* <div #actionCmd="ssvCommandRef" [ssvCommandRef]="{host: this, execute: removeHero$, canExecute: isValid$}">
|
|
181
|
+
* <button [ssvCommand]="actionCmd.command()" [ssvCommandParams]="[hero]">
|
|
182
|
+
* Remove
|
|
183
|
+
* </button>
|
|
184
|
+
* <button [ssvCommand]="actionCmd.command()" [ssvCommandParams]="[hero]">
|
|
185
|
+
* Remove
|
|
186
|
+
* </button>
|
|
187
|
+
* </div>
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
*/
|
|
191
|
+
declare class SsvCommandRef<TExecute extends ExecuteFn = ExecuteFn> implements OnInit {
|
|
192
|
+
#private;
|
|
193
|
+
readonly commandCreator: _angular_core.InputSignal<CommandCreator<TExecute>>;
|
|
194
|
+
readonly command: _angular_core.Signal<ICommand<TExecute>>;
|
|
195
|
+
ngOnInit(): void;
|
|
196
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SsvCommandRef<any>, never>;
|
|
197
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SsvCommandRef<any>, "[ssvCommandRef]", ["ssvCommandRef"], { "commandCreator": { "alias": "ssvCommandRef"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** @deprecated Use standalone instead. */
|
|
201
|
+
declare class SsvCommandModule {
|
|
202
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SsvCommandModule, never>;
|
|
203
|
+
static ɵmod: _angular_core.ɵɵNgModuleDeclaration<SsvCommandModule, never, [typeof SsvCommand, typeof SsvCommandRef], [typeof SsvCommand, typeof SsvCommandRef]>;
|
|
204
|
+
static ɵinj: _angular_core.ɵɵInjectorDeclaration<SsvCommandModule>;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Determines whether the arg object is of type `Command`. */
|
|
208
|
+
declare function isCommand<T extends ICommand>(arg: unknown | T): arg is T;
|
|
209
|
+
/** Determines whether the arg object is of type `CommandCreator`. */
|
|
210
|
+
declare function isCommandCreator<T extends CommandCreator>(arg: unknown | T): arg is T;
|
|
211
|
+
interface CanExecuteFormOptions {
|
|
212
|
+
/** Determines whether to check for validity. (defaults: true) */
|
|
213
|
+
validity?: boolean;
|
|
214
|
+
/** Determines whether to check whether UI has been touched. (defaults: true) */
|
|
215
|
+
dirty?: boolean;
|
|
216
|
+
}
|
|
217
|
+
/** Get can execute from form validity/pristine as an observable. */
|
|
218
|
+
declare function canExecuteFromNgForm(form: AbstractControl, options?: CanExecuteFormOptions): Observable<boolean>;
|
|
219
|
+
/** Can executed based on valid/dirty signal inputs. */
|
|
220
|
+
declare function canExecuteFromSignals(signals: {
|
|
221
|
+
valid: Signal<boolean>;
|
|
222
|
+
dirty: Signal<boolean>;
|
|
223
|
+
}, options?: CanExecuteFormOptions): Signal<boolean>;
|
|
224
|
+
|
|
225
|
+
declare const VERSION = "5.0.0-dev.113";
|
|
226
|
+
|
|
227
|
+
export { COMMAND_OPTIONS, Command, SsvCommand, SsvCommandModule, SsvCommandRef, VERSION, canExecuteFromNgForm, canExecuteFromSignals, command, commandAsync, isCommand, isCommandCreator, provideSsvCommandOptions };
|
|
228
|
+
export type { CanExecute, CanExecuteFormOptions, CommandCreateOptions, CommandCreator, CommandInput, CommandOptions, ExecuteFn, ICommand };
|
package/index.d.ts
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import * as _angular_core from '@angular/core';
|
|
2
|
-
import { InjectionToken, Provider, Signal, OnInit, Injector } from '@angular/core';
|
|
3
|
-
import { Observable } from 'rxjs';
|
|
4
|
-
import { AbstractControl } from '@angular/forms';
|
|
5
|
-
|
|
6
|
-
interface CommandOptions {
|
|
7
|
-
/**
|
|
8
|
-
* Css Class which gets added/removed on the Command element's host while Command `isExecuting$`.
|
|
9
|
-
*/
|
|
10
|
-
executingCssClass: string;
|
|
11
|
-
/** Determines whether the disabled will be handled by the directive or not.
|
|
12
|
-
* Disable handled by directive's doesn't always play nice when used with other component/pipe/directive and they also handle disabled.
|
|
13
|
-
* This disables the handling manually and need to pass explicitly `[disabled]="!saveCmd.canExecute"`.
|
|
14
|
-
*/
|
|
15
|
-
handleDisabled: boolean;
|
|
16
|
-
}
|
|
17
|
-
declare const COMMAND_OPTIONS: InjectionToken<CommandOptions>;
|
|
18
|
-
declare function provideSsvCommandOptions(options: Partial<CommandOptions> | ((defaults: Readonly<CommandOptions>) => Partial<CommandOptions>)): Provider[];
|
|
19
|
-
|
|
20
|
-
type ExecuteFn = (...args: any[]) => unknown;
|
|
21
|
-
type ExecuteAsyncFn = (...args: any[]) => Observable<unknown> | Promise<unknown>;
|
|
22
|
-
type CanExecute = (() => boolean) | Signal<boolean> | Observable<boolean>;
|
|
23
|
-
interface ICommand {
|
|
24
|
-
/** Determines whether the command is currently executing, as a snapshot value.
|
|
25
|
-
* @deprecated Use {@link $isExecuting} signal instead.
|
|
26
|
-
*/
|
|
27
|
-
readonly isExecuting: boolean;
|
|
28
|
-
/** Determines whether the command is currently executing, as a signal. */
|
|
29
|
-
readonly $isExecuting: Signal<boolean>;
|
|
30
|
-
/** Determines whether the command can execute or not, as a snapshot value.
|
|
31
|
-
* @deprecated Use {@link $canExecute} signal instead.
|
|
32
|
-
*/
|
|
33
|
-
readonly canExecute: boolean;
|
|
34
|
-
/** Determines whether the command can execute or not, as a signal. */
|
|
35
|
-
readonly $canExecute: Signal<boolean>;
|
|
36
|
-
/** Determines whether to auto destroy when having 0 subscribers (defaults to `true`).
|
|
37
|
-
* @deprecated Use using command/commandAsync is handled automatically.
|
|
38
|
-
*/
|
|
39
|
-
autoDestroy: boolean;
|
|
40
|
-
/** Execute function to invoke. */
|
|
41
|
-
execute(...args: unknown[]): void;
|
|
42
|
-
/** Disposes all resources held by subscriptions. */
|
|
43
|
-
destroy(): void;
|
|
44
|
-
/** Subscribe listener, in order to handle auto disposing.
|
|
45
|
-
* @deprecated Use using command/commandAsync is handled automatically.
|
|
46
|
-
*/
|
|
47
|
-
subscribe(): void;
|
|
48
|
-
/**
|
|
49
|
-
* Unsubscribe listener, in order to handle auto disposing.
|
|
50
|
-
* @deprecated Use using command/commandAsync is handled automatically.
|
|
51
|
-
*/
|
|
52
|
-
unsubscribe(): void;
|
|
53
|
-
}
|
|
54
|
-
interface CommandCreator {
|
|
55
|
-
execute: (...args: any[]) => Observable<unknown> | Promise<unknown> | void;
|
|
56
|
-
canExecute?: CanExecute | Function;
|
|
57
|
-
params?: unknown | unknown[];
|
|
58
|
-
isAsync?: boolean;
|
|
59
|
-
host: unknown;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
declare class SsvCommand implements OnInit {
|
|
63
|
-
#private;
|
|
64
|
-
readonly commandOrCreator: _angular_core.InputSignal<ICommand | CommandCreator>;
|
|
65
|
-
readonly ssvCommandOptions: _angular_core.InputSignal<Partial<CommandOptions>>;
|
|
66
|
-
readonly commandOptions: _angular_core.Signal<CommandOptions>;
|
|
67
|
-
readonly ssvCommandParams: _angular_core.InputSignal<unknown>;
|
|
68
|
-
readonly commandParams: _angular_core.Signal<unknown>;
|
|
69
|
-
readonly _hostClasses: _angular_core.Signal<string[]>;
|
|
70
|
-
private creatorParams;
|
|
71
|
-
get command(): ICommand;
|
|
72
|
-
private _command;
|
|
73
|
-
constructor();
|
|
74
|
-
ngOnInit(): void;
|
|
75
|
-
_handleClick(): void;
|
|
76
|
-
private trySetDisabled;
|
|
77
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SsvCommand, never>;
|
|
78
|
-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SsvCommand, "[ssvCommand]", ["ssvCommand"], { "commandOrCreator": { "alias": "ssvCommand"; "required": true; "isSignal": true; }; "ssvCommandOptions": { "alias": "ssvCommandOptions"; "required": false; "isSignal": true; }; "ssvCommandParams": { "alias": "ssvCommandParams"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Command creator ref, directive which allows creating Command in the template
|
|
83
|
-
* and associate it to a command (in order to share executions).
|
|
84
|
-
* @example
|
|
85
|
-
* ### Most common usage
|
|
86
|
-
* ```html
|
|
87
|
-
* <div #actionCmd="ssvCommandRef" [ssvCommandRef]="{host: this, execute: removeHero$, canExecute: isValid$}">
|
|
88
|
-
* <button [ssvCommand]="actionCmd.command" [ssvCommandParams]="hero">
|
|
89
|
-
* Remove
|
|
90
|
-
* </button>
|
|
91
|
-
* <button [ssvCommand]="actionCmd.command" [ssvCommandParams]="hero">
|
|
92
|
-
* Remove
|
|
93
|
-
* </button>
|
|
94
|
-
* </div>
|
|
95
|
-
* ```
|
|
96
|
-
*
|
|
97
|
-
*/
|
|
98
|
-
declare class SsvCommandRef implements OnInit {
|
|
99
|
-
#private;
|
|
100
|
-
readonly commandCreator: _angular_core.InputSignal<CommandCreator>;
|
|
101
|
-
get command(): ICommand;
|
|
102
|
-
private _command;
|
|
103
|
-
constructor();
|
|
104
|
-
ngOnInit(): void;
|
|
105
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SsvCommandRef, never>;
|
|
106
|
-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SsvCommandRef, "[ssvCommandRef]", ["ssvCommandRef"], { "commandCreator": { "alias": "ssvCommandRef"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** @deprecated Use standalone instead. */
|
|
110
|
-
declare class SsvCommandModule {
|
|
111
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SsvCommandModule, never>;
|
|
112
|
-
static ɵmod: _angular_core.ɵɵNgModuleDeclaration<SsvCommandModule, never, [typeof SsvCommand, typeof SsvCommandRef], [typeof SsvCommand, typeof SsvCommandRef]>;
|
|
113
|
-
static ɵinj: _angular_core.ɵɵInjectorDeclaration<SsvCommandModule>;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
interface CommandCreateOptions {
|
|
117
|
-
isAsync: boolean;
|
|
118
|
-
injector?: Injector;
|
|
119
|
-
}
|
|
120
|
-
/** Creates an async {@link Command}. Must be used within an injection context.
|
|
121
|
-
* NOTE: this auto injects `DestroyRef` and handles auto destroy. {@link ICommand.autoDestroy} should not be used.
|
|
122
|
-
*/
|
|
123
|
-
declare function commandAsync(execute: ExecuteAsyncFn, canExecute$?: CanExecute, opts?: Omit<CommandCreateOptions, "isAsync">): Command;
|
|
124
|
-
/** Creates a {@link Command}. Must be used within an injection context.
|
|
125
|
-
* NOTE: this auto injects `DestroyRef` and handles auto destroy. {@link ICommand.autoDestroy} should not be used.
|
|
126
|
-
*/
|
|
127
|
-
declare function command(execute: ExecuteFn, canExecute$?: CanExecute, opts?: CommandCreateOptions): Command;
|
|
128
|
-
/**
|
|
129
|
-
* Command object used to encapsulate information which is needed to perform an action.
|
|
130
|
-
*
|
|
131
|
-
*/
|
|
132
|
-
declare class Command implements ICommand {
|
|
133
|
-
get isExecuting(): boolean;
|
|
134
|
-
get canExecute(): boolean;
|
|
135
|
-
readonly $isExecuting: _angular_core.WritableSignal<boolean>;
|
|
136
|
-
readonly $canExecute: Signal<boolean>;
|
|
137
|
-
private readonly _$canExecute;
|
|
138
|
-
autoDestroy: boolean;
|
|
139
|
-
private executionPipe$;
|
|
140
|
-
private executionPipe$$;
|
|
141
|
-
private subscribersCount;
|
|
142
|
-
/**
|
|
143
|
-
* Creates an instance of Command.
|
|
144
|
-
*
|
|
145
|
-
* @param execute Execute function to invoke - use `isAsync: true` when `Observable<any>`.
|
|
146
|
-
* @param canExecute Observable which determines whether it can execute or not.
|
|
147
|
-
* @param isAsync Indicates that the execute function is async e.g. Observable.
|
|
148
|
-
* @deprecated Use {@link command} or {@link commandAsync} instead for creating instances.
|
|
149
|
-
*/
|
|
150
|
-
constructor(execute: ExecuteFn, canExecute$?: CanExecute, isAsync?: boolean, injector?: Injector);
|
|
151
|
-
/** Execute function to invoke. */
|
|
152
|
-
execute(...args: unknown[]): void;
|
|
153
|
-
/** Disposes all resources held by subscriptions. */
|
|
154
|
-
destroy(): void;
|
|
155
|
-
subscribe(): void;
|
|
156
|
-
unsubscribe(): void;
|
|
157
|
-
private buildExecutionPipe;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Async Command object used to encapsulate information which is needed to perform an action,
|
|
161
|
-
* which takes an execute function as Observable/Promise.
|
|
162
|
-
* @deprecated Use {@link commandAsync} instead.
|
|
163
|
-
*/
|
|
164
|
-
declare class CommandAsync extends Command {
|
|
165
|
-
/**
|
|
166
|
-
* @deprecated Use {@link commandAsync} instead to create an instance.
|
|
167
|
-
*/
|
|
168
|
-
constructor(execute: ExecuteAsyncFn, canExecute$?: CanExecute);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/** Determines whether the arg object is of type `Command`. */
|
|
172
|
-
declare function isCommand(arg: unknown): arg is ICommand;
|
|
173
|
-
/** Determines whether the arg object is of type `CommandCreator`. */
|
|
174
|
-
declare function isCommandCreator(arg: unknown): arg is CommandCreator;
|
|
175
|
-
interface CanExecuteFormOptions {
|
|
176
|
-
/** Determines whether to check for validity. (defaults: true) */
|
|
177
|
-
validity?: boolean;
|
|
178
|
-
/** Determines whether to check whether UI has been touched. (defaults: true) */
|
|
179
|
-
dirty?: boolean;
|
|
180
|
-
}
|
|
181
|
-
/** Get can execute from form validity/pristine as an observable. */
|
|
182
|
-
declare function canExecuteFromNgForm(form: AbstractControl, options?: CanExecuteFormOptions): Observable<boolean>;
|
|
183
|
-
/** Can executed based on valid/dirty signal inputs. */
|
|
184
|
-
declare function canExecuteFromSignals(signals: {
|
|
185
|
-
valid: Signal<boolean>;
|
|
186
|
-
dirty: Signal<boolean>;
|
|
187
|
-
}, options?: CanExecuteFormOptions): Signal<boolean>;
|
|
188
|
-
|
|
189
|
-
declare const VERSION = "4.0.0";
|
|
190
|
-
|
|
191
|
-
export { COMMAND_OPTIONS, Command, CommandAsync, SsvCommand, SsvCommandModule, SsvCommandRef, VERSION, canExecuteFromNgForm, canExecuteFromSignals, command, commandAsync, isCommand, isCommandCreator, provideSsvCommandOptions };
|
|
192
|
-
export type { CanExecute, CanExecuteFormOptions, CommandCreateOptions, CommandCreator, CommandOptions, ExecuteAsyncFn, ExecuteFn, ICommand };
|