@ng-atomic/common 19.140.4 → 19.144.4

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.
@@ -1,6 +1,73 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { inject, ElementRef, input, output, signal, effect, Directive } from '@angular/core';
3
3
 
4
+ function resolveFocusTarget(ctx) {
5
+ return ctx.focusTargetSelector
6
+ ? ctx.hostElement.querySelector(ctx.focusTargetSelector)
7
+ : null;
8
+ }
9
+ function focusHolder(ctx, target, focusTarget) {
10
+ const focused = ctx.hostElement.ownerDocument.activeElement;
11
+ if (!focused || focused === ctx.hostElement.ownerDocument.body)
12
+ return false;
13
+ if (focused === focusTarget || focused === ctx.hostElement)
14
+ return false;
15
+ if (!ctx.hostElement.contains(focused))
16
+ return false;
17
+ return focused === target || focused.contains(target);
18
+ }
19
+ function focusableAncestor(ctx, target, focusTarget) {
20
+ let el = target instanceof Element ? target : target.parentElement;
21
+ while (el && el !== ctx.hostElement) {
22
+ if (el !== focusTarget && el instanceof HTMLElement && (el.tabIndex >= 0 || el.isContentEditable)) {
23
+ return true;
24
+ }
25
+ el = el.parentElement;
26
+ }
27
+ return false;
28
+ }
29
+ function isClickConsumedByInnerWidget(ctx, target) {
30
+ if (!target || !ctx.hostElement.contains(target))
31
+ return false;
32
+ const focusTarget = resolveFocusTarget(ctx);
33
+ if (target === focusTarget || (focusTarget?.contains(target) ?? false))
34
+ return false;
35
+ return focusHolder(ctx, target, focusTarget) || focusableAncestor(ctx, target, focusTarget);
36
+ }
37
+
38
+ const FORWARD_RETRY_FRAMES = 5;
39
+ function focusableAt(ctx, x, y) {
40
+ const doc = ctx.hostElement.ownerDocument;
41
+ let el = doc.elementFromPoint(x, y);
42
+ while (el && el !== ctx.hostElement) {
43
+ if (el instanceof HTMLElement && (el.tabIndex >= 0 || el.isContentEditable))
44
+ return el;
45
+ el = el.parentElement;
46
+ }
47
+ return null;
48
+ }
49
+ function forwardActivationFocus(ctx, x, y, attempts = FORWARD_RETRY_FRAMES) {
50
+ if (ctx.focusTargetSelector && ctx.hostElement.querySelector(ctx.focusTargetSelector))
51
+ return;
52
+ const target = focusableAt(ctx, x, y);
53
+ if (target && ctx.hostElement.contains(target)) {
54
+ target.focus();
55
+ return;
56
+ }
57
+ if (attempts <= 0)
58
+ return;
59
+ ctx.hostElement.ownerDocument.defaultView?.requestAnimationFrame(() => forwardActivationFocus(ctx, x, y, attempts - 1));
60
+ }
61
+
62
+ function releaseFocusWithin(hostElement) {
63
+ const active = hostElement.ownerDocument.activeElement;
64
+ if (!(active instanceof HTMLElement) || !hostElement.contains(active))
65
+ return false;
66
+ active.blur();
67
+ return true;
68
+ }
69
+
70
+ const ACTIVE_CONTROL_DEACTIVATE_EVENT = 'active-control:request-deactivate';
4
71
  class ActiveControlEventHandlers {
5
72
  constructor(hostElement, isActive, onActiveChange, options = {}) {
6
73
  this.hostElement = hostElement;
@@ -25,6 +92,12 @@ class ActiveControlEventHandlers {
25
92
  : null;
26
93
  };
27
94
  this.addEventListener(window, 'mousedown', gestureStartHandler, { capture: true });
95
+ const gestureResetHandler = () => {
96
+ gestureStart = null;
97
+ justActivated = false;
98
+ };
99
+ this.addEventListener(window, 'dragend', gestureResetHandler, { capture: true });
100
+ this.addEventListener(window, 'blur', gestureResetHandler);
28
101
  const mousedownHandler = (e) => {
29
102
  if (!this.isActive()) {
30
103
  this.setActive(true);
@@ -50,6 +123,7 @@ class ActiveControlEventHandlers {
50
123
  }
51
124
  if (justActivated) {
52
125
  justActivated = false;
126
+ forwardActivationFocus({ hostElement: this.hostElement, focusTargetSelector: this.options.focusTargetSelector }, e.clientX, e.clientY);
53
127
  return;
54
128
  }
55
129
  if (!start) {
@@ -59,11 +133,18 @@ class ActiveControlEventHandlers {
59
133
  if (moved) {
60
134
  return;
61
135
  }
136
+ if (isClickConsumedByInnerWidget({ hostElement: this.hostElement, focusTargetSelector: this.options.focusTargetSelector }, e.target)) {
137
+ return;
138
+ }
62
139
  if (this.isActive()) {
63
140
  setTimeout(() => this.setActive(false), 0);
64
141
  }
65
142
  };
66
143
  this.addEventListener(window, 'mouseup', mouseupHandler, { capture: true });
144
+ this.addEventListener(this.hostElement, ACTIVE_CONTROL_DEACTIVATE_EVENT, () => {
145
+ if (this.isActive())
146
+ this.setActive(false);
147
+ });
67
148
  const documentClickListener = (e) => {
68
149
  if (!this.hostElement.contains(e.target) && this.isActive()) {
69
150
  this.setActive(false);
@@ -149,6 +230,8 @@ class ActiveControlEventHandlers {
149
230
  this.setActive(!this.isActive());
150
231
  }
151
232
  setActive(active) {
233
+ if (!active)
234
+ releaseFocusWithin(this.hostElement);
152
235
  this.isActive.set(active);
153
236
  this.onActiveChange(active);
154
237
  }
@@ -274,4 +357,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
274
357
  * Generated bundle index. Do not edit.
275
358
  */
276
359
 
277
- export { ActiveControlDirective };
360
+ export { ACTIVE_CONTROL_DEACTIVATE_EVENT, ActiveControlDirective };
@@ -0,0 +1,46 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, ElementRef, input, Directive } from '@angular/core';
3
+
4
+ const CONTAINED_EVENTS = [
5
+ 'mousedown',
6
+ 'click',
7
+ 'dblclick',
8
+ 'touchstart',
9
+ 'touchmove',
10
+ 'pointerdown',
11
+ 'pointermove',
12
+ 'wheel',
13
+ ];
14
+ class ContainEventsDirective {
15
+ constructor() {
16
+ this.el = inject(ElementRef);
17
+ this.appContainEvents = input.required(...(ngDevMode ? [{ debugName: "appContainEvents" }] : []));
18
+ this.handler = (event) => {
19
+ if (this.appContainEvents())
20
+ event.stopPropagation();
21
+ };
22
+ for (const name of CONTAINED_EVENTS) {
23
+ this.el.nativeElement.addEventListener(name, this.handler);
24
+ }
25
+ }
26
+ ngOnDestroy() {
27
+ for (const name of CONTAINED_EVENTS) {
28
+ this.el.nativeElement.removeEventListener(name, this.handler);
29
+ }
30
+ }
31
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ContainEventsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
32
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.6", type: ContainEventsDirective, isStandalone: true, selector: "[appContainEvents]", inputs: { appContainEvents: { classPropertyName: "appContainEvents", publicName: "appContainEvents", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
33
+ }
34
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ContainEventsDirective, decorators: [{
35
+ type: Directive,
36
+ args: [{
37
+ selector: '[appContainEvents]',
38
+ standalone: true,
39
+ }]
40
+ }], ctorParameters: () => [], propDecorators: { appContainEvents: [{ type: i0.Input, args: [{ isSignal: true, alias: "appContainEvents", required: true }] }] } });
41
+
42
+ /**
43
+ * Generated bundle index. Do not edit.
44
+ */
45
+
46
+ export { ContainEventsDirective };
@@ -135,6 +135,73 @@ function bufferWhenEditing(editingStateManager) {
135
135
  };
136
136
  }
137
137
 
138
+ function resolveFocusTarget(ctx) {
139
+ return ctx.focusTargetSelector
140
+ ? ctx.hostElement.querySelector(ctx.focusTargetSelector)
141
+ : null;
142
+ }
143
+ function focusHolder(ctx, target, focusTarget) {
144
+ const focused = ctx.hostElement.ownerDocument.activeElement;
145
+ if (!focused || focused === ctx.hostElement.ownerDocument.body)
146
+ return false;
147
+ if (focused === focusTarget || focused === ctx.hostElement)
148
+ return false;
149
+ if (!ctx.hostElement.contains(focused))
150
+ return false;
151
+ return focused === target || focused.contains(target);
152
+ }
153
+ function focusableAncestor(ctx, target, focusTarget) {
154
+ let el = target instanceof Element ? target : target.parentElement;
155
+ while (el && el !== ctx.hostElement) {
156
+ if (el !== focusTarget && el instanceof HTMLElement && (el.tabIndex >= 0 || el.isContentEditable)) {
157
+ return true;
158
+ }
159
+ el = el.parentElement;
160
+ }
161
+ return false;
162
+ }
163
+ function isClickConsumedByInnerWidget(ctx, target) {
164
+ if (!target || !ctx.hostElement.contains(target))
165
+ return false;
166
+ const focusTarget = resolveFocusTarget(ctx);
167
+ if (target === focusTarget || (focusTarget?.contains(target) ?? false))
168
+ return false;
169
+ return focusHolder(ctx, target, focusTarget) || focusableAncestor(ctx, target, focusTarget);
170
+ }
171
+
172
+ const FORWARD_RETRY_FRAMES = 5;
173
+ function focusableAt(ctx, x, y) {
174
+ const doc = ctx.hostElement.ownerDocument;
175
+ let el = doc.elementFromPoint(x, y);
176
+ while (el && el !== ctx.hostElement) {
177
+ if (el instanceof HTMLElement && (el.tabIndex >= 0 || el.isContentEditable))
178
+ return el;
179
+ el = el.parentElement;
180
+ }
181
+ return null;
182
+ }
183
+ function forwardActivationFocus(ctx, x, y, attempts = FORWARD_RETRY_FRAMES) {
184
+ if (ctx.focusTargetSelector && ctx.hostElement.querySelector(ctx.focusTargetSelector))
185
+ return;
186
+ const target = focusableAt(ctx, x, y);
187
+ if (target && ctx.hostElement.contains(target)) {
188
+ target.focus();
189
+ return;
190
+ }
191
+ if (attempts <= 0)
192
+ return;
193
+ ctx.hostElement.ownerDocument.defaultView?.requestAnimationFrame(() => forwardActivationFocus(ctx, x, y, attempts - 1));
194
+ }
195
+
196
+ function releaseFocusWithin(hostElement) {
197
+ const active = hostElement.ownerDocument.activeElement;
198
+ if (!(active instanceof HTMLElement) || !hostElement.contains(active))
199
+ return false;
200
+ active.blur();
201
+ return true;
202
+ }
203
+
204
+ const ACTIVE_CONTROL_DEACTIVATE_EVENT = 'active-control:request-deactivate';
138
205
  class ActiveControlEventHandlers {
139
206
  constructor(hostElement, isActive, onActiveChange, options = {}) {
140
207
  this.hostElement = hostElement;
@@ -159,6 +226,12 @@ class ActiveControlEventHandlers {
159
226
  : null;
160
227
  };
161
228
  this.addEventListener(window, 'mousedown', gestureStartHandler, { capture: true });
229
+ const gestureResetHandler = () => {
230
+ gestureStart = null;
231
+ justActivated = false;
232
+ };
233
+ this.addEventListener(window, 'dragend', gestureResetHandler, { capture: true });
234
+ this.addEventListener(window, 'blur', gestureResetHandler);
162
235
  const mousedownHandler = (e) => {
163
236
  if (!this.isActive()) {
164
237
  this.setActive(true);
@@ -184,6 +257,7 @@ class ActiveControlEventHandlers {
184
257
  }
185
258
  if (justActivated) {
186
259
  justActivated = false;
260
+ forwardActivationFocus({ hostElement: this.hostElement, focusTargetSelector: this.options.focusTargetSelector }, e.clientX, e.clientY);
187
261
  return;
188
262
  }
189
263
  if (!start) {
@@ -193,11 +267,18 @@ class ActiveControlEventHandlers {
193
267
  if (moved) {
194
268
  return;
195
269
  }
270
+ if (isClickConsumedByInnerWidget({ hostElement: this.hostElement, focusTargetSelector: this.options.focusTargetSelector }, e.target)) {
271
+ return;
272
+ }
196
273
  if (this.isActive()) {
197
274
  setTimeout(() => this.setActive(false), 0);
198
275
  }
199
276
  };
200
277
  this.addEventListener(window, 'mouseup', mouseupHandler, { capture: true });
278
+ this.addEventListener(this.hostElement, ACTIVE_CONTROL_DEACTIVATE_EVENT, () => {
279
+ if (this.isActive())
280
+ this.setActive(false);
281
+ });
201
282
  const documentClickListener = (e) => {
202
283
  if (!this.hostElement.contains(e.target) && this.isActive()) {
203
284
  this.setActive(false);
@@ -283,6 +364,8 @@ class ActiveControlEventHandlers {
283
364
  this.setActive(!this.isActive());
284
365
  }
285
366
  setActive(active) {
367
+ if (!active)
368
+ releaseFocusWithin(this.hostElement);
286
369
  this.isActive.set(active);
287
370
  this.onActiveChange(active);
288
371
  }
@@ -404,8 +487,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
404
487
  }]
405
488
  }], ctorParameters: () => [], propDecorators: { scrollSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollSelector", required: false }] }], scrollSelectors: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollSelectors", required: false }] }], disableStopPropagation: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableStopPropagation", required: false }] }], disableScrollLock: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableScrollLock", required: false }] }], disableNodrag: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableNodrag", required: false }] }], focusTargetSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "focusTargetSelector", required: false }] }], activeChange: [{ type: i0.Output, args: ["activeChange"] }] } });
406
489
 
490
+ const CONTAINED_EVENTS = [
491
+ 'mousedown',
492
+ 'click',
493
+ 'dblclick',
494
+ 'touchstart',
495
+ 'touchmove',
496
+ 'pointerdown',
497
+ 'pointermove',
498
+ 'wheel',
499
+ ];
500
+ class ContainEventsDirective {
501
+ constructor() {
502
+ this.el = inject(ElementRef);
503
+ this.appContainEvents = input.required(...(ngDevMode ? [{ debugName: "appContainEvents" }] : []));
504
+ this.handler = (event) => {
505
+ if (this.appContainEvents())
506
+ event.stopPropagation();
507
+ };
508
+ for (const name of CONTAINED_EVENTS) {
509
+ this.el.nativeElement.addEventListener(name, this.handler);
510
+ }
511
+ }
512
+ ngOnDestroy() {
513
+ for (const name of CONTAINED_EVENTS) {
514
+ this.el.nativeElement.removeEventListener(name, this.handler);
515
+ }
516
+ }
517
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ContainEventsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
518
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.6", type: ContainEventsDirective, isStandalone: true, selector: "[appContainEvents]", inputs: { appContainEvents: { classPropertyName: "appContainEvents", publicName: "appContainEvents", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
519
+ }
520
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ContainEventsDirective, decorators: [{
521
+ type: Directive,
522
+ args: [{
523
+ selector: '[appContainEvents]',
524
+ standalone: true,
525
+ }]
526
+ }], ctorParameters: () => [], propDecorators: { appContainEvents: [{ type: i0.Input, args: [{ isSignal: true, alias: "appContainEvents", required: true }] }] } });
527
+
407
528
  /**
408
529
  * Generated bundle index. Do not edit.
409
530
  */
410
531
 
411
- export { ActiveControlDirective, EditingStateManager, NgAtomicCommonModule, bufferWhenEditing, pauseWhenEditing, provideNgAtomicCommon };
532
+ export { ACTIVE_CONTROL_DEACTIVATE_EVENT, ActiveControlDirective, ContainEventsDirective, EditingStateManager, NgAtomicCommonModule, bufferWhenEditing, pauseWhenEditing, provideNgAtomicCommon };
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@ng-atomic/common",
3
- "version": "19.140.4",
3
+ "version": "19.144.4",
4
4
  "license": "MIT",
5
5
  "peerDependencies": {
6
- "@nx-ddd/core": "19.140.4",
7
- "@nx-ddd/common": "19.140.4"
6
+ "@nx-ddd/core": "19.144.4",
7
+ "@nx-ddd/common": "19.144.4"
8
8
  },
9
9
  "dependencies": {
10
10
  "tslib": "^2.3.0"
@@ -23,6 +23,10 @@
23
23
  "types": "./types/ng-atomic-common-directives-active-control.d.ts",
24
24
  "default": "./fesm2022/ng-atomic-common-directives-active-control.mjs"
25
25
  },
26
+ "./directives/contain-events": {
27
+ "types": "./types/ng-atomic-common-directives-contain-events.d.ts",
28
+ "default": "./fesm2022/ng-atomic-common-directives-contain-events.mjs"
29
+ },
26
30
  "./directives/fallback-src": {
27
31
  "types": "./types/ng-atomic-common-directives-fallback-src.d.ts",
28
32
  "default": "./fesm2022/ng-atomic-common-directives-fallback-src.mjs"
@@ -23,4 +23,6 @@ declare class ActiveControlDirective implements OnDestroy {
23
23
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ActiveControlDirective, "[appActiveControl]", never, { "scrollSelector": { "alias": "scrollSelector"; "required": false; "isSignal": true; }; "scrollSelectors": { "alias": "scrollSelectors"; "required": false; "isSignal": true; }; "disableStopPropagation": { "alias": "disableStopPropagation"; "required": false; "isSignal": true; }; "disableScrollLock": { "alias": "disableScrollLock"; "required": false; "isSignal": true; }; "disableNodrag": { "alias": "disableNodrag"; "required": false; "isSignal": true; }; "focusTargetSelector": { "alias": "focusTargetSelector"; "required": false; "isSignal": true; }; }, { "activeChange": "activeChange"; }, never, never, true, never>;
24
24
  }
25
25
 
26
- export { ActiveControlDirective };
26
+ declare const ACTIVE_CONTROL_DEACTIVATE_EVENT = "active-control:request-deactivate";
27
+
28
+ export { ACTIVE_CONTROL_DEACTIVATE_EVENT, ActiveControlDirective };
@@ -0,0 +1,14 @@
1
+ import * as i0 from '@angular/core';
2
+ import { OnDestroy } from '@angular/core';
3
+
4
+ declare class ContainEventsDirective implements OnDestroy {
5
+ private readonly el;
6
+ readonly appContainEvents: i0.InputSignal<boolean>;
7
+ private readonly handler;
8
+ constructor();
9
+ ngOnDestroy(): void;
10
+ static ɵfac: i0.ɵɵFactoryDeclaration<ContainEventsDirective, never>;
11
+ static ɵdir: i0.ɵɵDirectiveDeclaration<ContainEventsDirective, "[appContainEvents]", never, { "appContainEvents": { "alias": "appContainEvents"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
12
+ }
13
+
14
+ export { ContainEventsDirective };
@@ -51,4 +51,16 @@ declare class ActiveControlDirective implements OnDestroy {
51
51
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ActiveControlDirective, "[appActiveControl]", never, { "scrollSelector": { "alias": "scrollSelector"; "required": false; "isSignal": true; }; "scrollSelectors": { "alias": "scrollSelectors"; "required": false; "isSignal": true; }; "disableStopPropagation": { "alias": "disableStopPropagation"; "required": false; "isSignal": true; }; "disableScrollLock": { "alias": "disableScrollLock"; "required": false; "isSignal": true; }; "disableNodrag": { "alias": "disableNodrag"; "required": false; "isSignal": true; }; "focusTargetSelector": { "alias": "focusTargetSelector"; "required": false; "isSignal": true; }; }, { "activeChange": "activeChange"; }, never, never, true, never>;
52
52
  }
53
53
 
54
- export { ActiveControlDirective, EditingStateManager, NgAtomicCommonModule, bufferWhenEditing, pauseWhenEditing, provideNgAtomicCommon };
54
+ declare const ACTIVE_CONTROL_DEACTIVATE_EVENT = "active-control:request-deactivate";
55
+
56
+ declare class ContainEventsDirective implements OnDestroy {
57
+ private readonly el;
58
+ readonly appContainEvents: _angular_core.InputSignal<boolean>;
59
+ private readonly handler;
60
+ constructor();
61
+ ngOnDestroy(): void;
62
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContainEventsDirective, never>;
63
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ContainEventsDirective, "[appContainEvents]", never, { "appContainEvents": { "alias": "appContainEvents"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
64
+ }
65
+
66
+ export { ACTIVE_CONTROL_DEACTIVATE_EVENT, ActiveControlDirective, ContainEventsDirective, EditingStateManager, NgAtomicCommonModule, bufferWhenEditing, pauseWhenEditing, provideNgAtomicCommon };