ng-primitives 0.111.0 → 0.112.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,329 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { Signal, WritableSignal } from '@angular/core';
3
+ import { Observable } from 'rxjs';
4
+ import { NumberInput, BooleanInput } from '@angular/cdk/coercion';
5
+
6
+ /**
7
+ * Public state surface for the NumberField primitive.
8
+ */
9
+ interface NgpNumberFieldState {
10
+ /**
11
+ * The id of the number field.
12
+ */
13
+ readonly id: Signal<string>;
14
+ /**
15
+ * The current value.
16
+ */
17
+ readonly value: WritableSignal<number | null>;
18
+ /**
19
+ * The minimum value.
20
+ */
21
+ readonly min: Signal<number>;
22
+ /**
23
+ * The maximum value.
24
+ */
25
+ readonly max: Signal<number>;
26
+ /**
27
+ * The step value.
28
+ */
29
+ readonly step: Signal<number>;
30
+ /**
31
+ * The large step value (used with Shift key).
32
+ */
33
+ readonly largeStep: Signal<number>;
34
+ /**
35
+ * Whether the number field is disabled (includes form control state).
36
+ */
37
+ readonly disabled: WritableSignal<boolean>;
38
+ /**
39
+ * Whether the number field is readonly.
40
+ */
41
+ readonly readonly: WritableSignal<boolean>;
42
+ /**
43
+ * Whether the increment button should be disabled.
44
+ */
45
+ readonly canIncrement: Signal<boolean>;
46
+ /**
47
+ * Whether the decrement button should be disabled.
48
+ */
49
+ readonly canDecrement: Signal<boolean>;
50
+ /**
51
+ * Emit when the value changes.
52
+ */
53
+ readonly valueChange: Observable<number | null>;
54
+ /**
55
+ * Set the current value (clamped and stepped).
56
+ */
57
+ setValue(value: number | null): void;
58
+ /**
59
+ * Increment the value by one step.
60
+ */
61
+ increment(multiplier?: number): void;
62
+ /**
63
+ * Decrement the value by one step.
64
+ */
65
+ decrement(multiplier?: number): void;
66
+ /**
67
+ * Set the disabled state.
68
+ */
69
+ setDisabled(disabled: boolean): void;
70
+ /**
71
+ * Set the readonly state.
72
+ */
73
+ setReadonly(readonly: boolean): void;
74
+ /** @internal */
75
+ registerInputCommit(commitFn: () => void): void;
76
+ }
77
+ /**
78
+ * Inputs for configuring the NumberField primitive.
79
+ */
80
+ interface NgpNumberFieldProps {
81
+ /**
82
+ * The id of the number field.
83
+ */
84
+ readonly id?: Signal<string>;
85
+ /**
86
+ * The current value.
87
+ */
88
+ readonly value?: Signal<number | null>;
89
+ /**
90
+ * The minimum value.
91
+ */
92
+ readonly min?: Signal<number>;
93
+ /**
94
+ * The maximum value.
95
+ */
96
+ readonly max?: Signal<number>;
97
+ /**
98
+ * The step value.
99
+ */
100
+ readonly step?: Signal<number>;
101
+ /**
102
+ * The large step value (used with Shift key).
103
+ */
104
+ readonly largeStep?: Signal<number>;
105
+ /**
106
+ * Whether the number field is disabled.
107
+ */
108
+ readonly disabled?: Signal<boolean>;
109
+ /**
110
+ * Whether the number field is readonly.
111
+ */
112
+ readonly readonly?: Signal<boolean>;
113
+ /**
114
+ * Callback fired when the value changes.
115
+ */
116
+ readonly onValueChange?: (value: number | null) => void;
117
+ }
118
+ declare const ngpNumberField: ({ id, value: _value, min, max, step, largeStep: _largeStep, disabled: _disabled, readonly: _readonly, onValueChange, }: NgpNumberFieldProps) => NgpNumberFieldState;
119
+ declare const injectNumberFieldState: {
120
+ (): Signal<NgpNumberFieldState>;
121
+ (options: {
122
+ hoisted: true;
123
+ optional?: boolean;
124
+ skipSelf?: boolean;
125
+ }): Signal<NgpNumberFieldState | null>;
126
+ (options?: {
127
+ hoisted?: boolean;
128
+ optional?: boolean;
129
+ skipSelf?: boolean;
130
+ }): Signal<NgpNumberFieldState> | Signal<NgpNumberFieldState | null>;
131
+ };
132
+ declare const provideNumberFieldState: (opts?: {
133
+ inherit?: boolean;
134
+ }) => _angular_core.FactoryProvider;
135
+
136
+ /**
137
+ * Apply the `ngpNumberField` directive to an element that represents the number field
138
+ * and contains the input, increment, and decrement buttons.
139
+ */
140
+ declare class NgpNumberField {
141
+ /**
142
+ * The id of the number field. If not provided, a unique id will be generated.
143
+ */
144
+ readonly id: _angular_core.InputSignal<string>;
145
+ /**
146
+ * The value of the number field.
147
+ */
148
+ readonly value: _angular_core.InputSignalWithTransform<number | null, NumberInput>;
149
+ /**
150
+ * Emits when the value changes.
151
+ */
152
+ readonly valueChange: _angular_core.OutputEmitterRef<number | null>;
153
+ /**
154
+ * The minimum value.
155
+ */
156
+ readonly min: _angular_core.InputSignalWithTransform<number, NumberInput>;
157
+ /**
158
+ * The maximum value.
159
+ */
160
+ readonly max: _angular_core.InputSignalWithTransform<number, NumberInput>;
161
+ /**
162
+ * The step value.
163
+ */
164
+ readonly step: _angular_core.InputSignalWithTransform<number, NumberInput>;
165
+ /**
166
+ * The large step value (used with Shift key).
167
+ */
168
+ readonly largeStep: _angular_core.InputSignalWithTransform<number, NumberInput>;
169
+ /**
170
+ * The disabled state of the number field.
171
+ */
172
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, BooleanInput>;
173
+ /**
174
+ * The readonly state of the number field.
175
+ */
176
+ readonly readonly: _angular_core.InputSignalWithTransform<boolean, BooleanInput>;
177
+ /**
178
+ * @internal
179
+ */
180
+ protected readonly state: NgpNumberFieldState;
181
+ /**
182
+ * Set the value of the number field.
183
+ */
184
+ setValue(value: number | null): void;
185
+ /**
186
+ * Increment the value.
187
+ */
188
+ increment(multiplier?: number): void;
189
+ /**
190
+ * Decrement the value.
191
+ */
192
+ decrement(multiplier?: number): void;
193
+ /**
194
+ * Set the disabled state.
195
+ */
196
+ setDisabled(disabled: boolean): void;
197
+ /**
198
+ * Set the readonly state.
199
+ */
200
+ setReadonly(readonly: boolean): void;
201
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgpNumberField, never>;
202
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgpNumberField, "[ngpNumberField]", ["ngpNumberField"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "ngpNumberFieldValue"; "required": false; "isSignal": true; }; "min": { "alias": "ngpNumberFieldMin"; "required": false; "isSignal": true; }; "max": { "alias": "ngpNumberFieldMax"; "required": false; "isSignal": true; }; "step": { "alias": "ngpNumberFieldStep"; "required": false; "isSignal": true; }; "largeStep": { "alias": "ngpNumberFieldLargeStep"; "required": false; "isSignal": true; }; "disabled": { "alias": "ngpNumberFieldDisabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "ngpNumberFieldReadonly"; "required": false; "isSignal": true; }; }, { "valueChange": "ngpNumberFieldValueChange"; }, never, never, true, never>;
203
+ }
204
+
205
+ /**
206
+ * Apply the `ngpNumberFieldInput` directive to an input element within a number field.
207
+ */
208
+ declare class NgpNumberFieldInput {
209
+ /**
210
+ * Whether mouse wheel changes the value when the input is focused.
211
+ */
212
+ readonly allowWheelScrub: _angular_core.InputSignalWithTransform<boolean, BooleanInput>;
213
+ constructor();
214
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgpNumberFieldInput, never>;
215
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgpNumberFieldInput, "[ngpNumberFieldInput]", ["ngpNumberFieldInput"], { "allowWheelScrub": { "alias": "ngpNumberFieldInputAllowWheelScrub"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
216
+ }
217
+
218
+ /**
219
+ * Public state surface for the NumberField Input primitive.
220
+ */
221
+ interface NgpNumberFieldInputState {
222
+ /**
223
+ * Focus the input element.
224
+ */
225
+ focus(): void;
226
+ }
227
+ /**
228
+ * Inputs for configuring the NumberField Input primitive.
229
+ */
230
+ interface NgpNumberFieldInputProps {
231
+ /**
232
+ * Whether mouse wheel changes the value.
233
+ */
234
+ readonly allowWheelScrub?: Signal<boolean>;
235
+ }
236
+ declare const ngpNumberFieldInput: ({ allowWheelScrub }: NgpNumberFieldInputProps) => NgpNumberFieldInputState;
237
+ declare const injectNumberFieldInputState: {
238
+ (): Signal<NgpNumberFieldInputState>;
239
+ (options: {
240
+ hoisted: true;
241
+ optional?: boolean;
242
+ skipSelf?: boolean;
243
+ }): Signal<NgpNumberFieldInputState | null>;
244
+ (options?: {
245
+ hoisted?: boolean;
246
+ optional?: boolean;
247
+ skipSelf?: boolean;
248
+ }): Signal<NgpNumberFieldInputState> | Signal<NgpNumberFieldInputState | null>;
249
+ };
250
+ declare const provideNumberFieldInputState: (opts?: {
251
+ inherit?: boolean;
252
+ }) => _angular_core.FactoryProvider;
253
+
254
+ /**
255
+ * Apply the `ngpNumberFieldIncrement` directive to a button element that increments the number field value.
256
+ */
257
+ declare class NgpNumberFieldIncrement {
258
+ constructor();
259
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgpNumberFieldIncrement, never>;
260
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgpNumberFieldIncrement, "[ngpNumberFieldIncrement]", ["ngpNumberFieldIncrement"], {}, {}, never, never, true, never>;
261
+ }
262
+
263
+ /**
264
+ * Public state surface for the NumberField Increment primitive.
265
+ */
266
+ interface NgpNumberFieldIncrementState {
267
+ }
268
+ /**
269
+ * Inputs for configuring the NumberField Increment primitive.
270
+ */
271
+ interface NgpNumberFieldIncrementProps {
272
+ }
273
+ declare const ngpNumberFieldIncrement: ({}: NgpNumberFieldIncrementProps) => NgpNumberFieldIncrementState;
274
+ declare const injectNumberFieldIncrementState: {
275
+ (): _angular_core.Signal<NgpNumberFieldIncrementState>;
276
+ (options: {
277
+ hoisted: true;
278
+ optional?: boolean;
279
+ skipSelf?: boolean;
280
+ }): _angular_core.Signal<NgpNumberFieldIncrementState | null>;
281
+ (options?: {
282
+ hoisted?: boolean;
283
+ optional?: boolean;
284
+ skipSelf?: boolean;
285
+ }): _angular_core.Signal<NgpNumberFieldIncrementState> | _angular_core.Signal<NgpNumberFieldIncrementState | null>;
286
+ };
287
+ declare const provideNumberFieldIncrementState: (opts?: {
288
+ inherit?: boolean;
289
+ }) => _angular_core.FactoryProvider;
290
+
291
+ /**
292
+ * Apply the `ngpNumberFieldDecrement` directive to a button element that decrements the number field value.
293
+ */
294
+ declare class NgpNumberFieldDecrement {
295
+ constructor();
296
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgpNumberFieldDecrement, never>;
297
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgpNumberFieldDecrement, "[ngpNumberFieldDecrement]", ["ngpNumberFieldDecrement"], {}, {}, never, never, true, never>;
298
+ }
299
+
300
+ /**
301
+ * Public state surface for the NumberField Decrement primitive.
302
+ */
303
+ interface NgpNumberFieldDecrementState {
304
+ }
305
+ /**
306
+ * Inputs for configuring the NumberField Decrement primitive.
307
+ */
308
+ interface NgpNumberFieldDecrementProps {
309
+ }
310
+ declare const ngpNumberFieldDecrement: ({}: NgpNumberFieldDecrementProps) => NgpNumberFieldDecrementState;
311
+ declare const injectNumberFieldDecrementState: {
312
+ (): _angular_core.Signal<NgpNumberFieldDecrementState>;
313
+ (options: {
314
+ hoisted: true;
315
+ optional?: boolean;
316
+ skipSelf?: boolean;
317
+ }): _angular_core.Signal<NgpNumberFieldDecrementState | null>;
318
+ (options?: {
319
+ hoisted?: boolean;
320
+ optional?: boolean;
321
+ skipSelf?: boolean;
322
+ }): _angular_core.Signal<NgpNumberFieldDecrementState> | _angular_core.Signal<NgpNumberFieldDecrementState | null>;
323
+ };
324
+ declare const provideNumberFieldDecrementState: (opts?: {
325
+ inherit?: boolean;
326
+ }) => _angular_core.FactoryProvider;
327
+
328
+ export { NgpNumberField, NgpNumberFieldDecrement, NgpNumberFieldIncrement, NgpNumberFieldInput, injectNumberFieldDecrementState, injectNumberFieldIncrementState, injectNumberFieldInputState, injectNumberFieldState, ngpNumberField, ngpNumberFieldDecrement, ngpNumberFieldIncrement, ngpNumberFieldInput, provideNumberFieldDecrementState, provideNumberFieldIncrementState, provideNumberFieldInputState, provideNumberFieldState };
329
+ export type { NgpNumberFieldDecrementProps, NgpNumberFieldDecrementState, NgpNumberFieldIncrementProps, NgpNumberFieldIncrementState, NgpNumberFieldInputProps, NgpNumberFieldInputState, NgpNumberFieldProps, NgpNumberFieldState };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "ng-primitives",
3
3
  "description": "Angular Primitives is a low-level headless UI component library with a focus on accessibility, customization, and developer experience. ",
4
4
  "license": "Apache-2.0",
5
- "version": "0.111.0",
5
+ "version": "0.112.0",
6
6
  "keywords": [
7
7
  "angular",
8
8
  "primitives",
@@ -164,6 +164,10 @@
164
164
  "types": "./navigation-menu/index.d.ts",
165
165
  "default": "./fesm2022/ng-primitives-navigation-menu.mjs"
166
166
  },
167
+ "./number-field": {
168
+ "types": "./number-field/index.d.ts",
169
+ "default": "./fesm2022/ng-primitives-number-field.mjs"
170
+ },
167
171
  "./pagination": {
168
172
  "types": "./pagination/index.d.ts",
169
173
  "default": "./fesm2022/ng-primitives-pagination.mjs"
package/portal/index.d.ts CHANGED
@@ -285,6 +285,8 @@ declare class NgpOverlay<T = unknown> implements CooldownOverlay {
285
285
  private readonly cooldownManager;
286
286
  /** Access any parent overlays */
287
287
  private readonly parentOverlay;
288
+ /** Track child overlays for outside click detection */
289
+ private readonly childOverlays;
288
290
  /** Signal tracking the portal instance */
289
291
  private readonly portal;
290
292
  /** Signal tracking the overlay position */
@@ -394,6 +396,21 @@ declare class NgpOverlay<T = unknown> implements CooldownOverlay {
394
396
  * Get the elements of the overlay
395
397
  */
396
398
  getElements(): HTMLElement[];
399
+ /**
400
+ * Register a child overlay for outside click detection.
401
+ * @internal
402
+ */
403
+ registerChildOverlay(child: NgpOverlay): void;
404
+ /**
405
+ * Unregister a child overlay.
406
+ * @internal
407
+ */
408
+ unregisterChildOverlay(child: NgpOverlay): void;
409
+ /**
410
+ * Check if the event path includes any child overlay elements (recursively).
411
+ * @internal
412
+ */
413
+ isInsideChildOverlay(path: EventTarget[]): boolean;
397
414
  /**
398
415
  * Internal method to create the overlay
399
416
  * @param skipCooldown If true, skip registering with the cooldown manager
@@ -0,0 +1,109 @@
1
+ import { Component } from '@angular/core';
2
+ import {
3
+ NgpNumberField,
4
+ NgpNumberFieldDecrement,
5
+ NgpNumberFieldIncrement,
6
+ NgpNumberFieldInput,
7
+ } from 'ng-primitives/number-field';
8
+
9
+ @Component({
10
+ selector: '<%= prefix %>-number-field',
11
+ hostDirectives: [
12
+ {
13
+ directive: NgpNumberField,
14
+ inputs: [
15
+ 'ngpNumberFieldValue:value',
16
+ 'ngpNumberFieldMin:min',
17
+ 'ngpNumberFieldMax:max',
18
+ 'ngpNumberFieldStep:step',
19
+ 'ngpNumberFieldLargeStep:largeStep',
20
+ 'ngpNumberFieldDisabled:disabled',
21
+ 'ngpNumberFieldReadonly:readonly',
22
+ ],
23
+ outputs: ['ngpNumberFieldValueChange:valueChange'],
24
+ },
25
+ ],
26
+ imports: [NgpNumberFieldInput, NgpNumberFieldIncrement, NgpNumberFieldDecrement],
27
+ template: `
28
+ <button ngpNumberFieldDecrement aria-label="Decrement">−</button>
29
+ <input ngpNumberFieldInput />
30
+ <button ngpNumberFieldIncrement aria-label="Increment">+</button>
31
+ `,
32
+ styles: `
33
+ /* These styles rely on CSS variables that can be imported from ng-primitives/example-theme/index.css in your global styles */
34
+
35
+ :host {
36
+ display: inline-flex;
37
+ align-items: center;
38
+ border-radius: 8px;
39
+ box-shadow: var(--ngp-input-shadow);
40
+ background-color: var(--ngp-background);
41
+ overflow: hidden;
42
+ }
43
+
44
+ :host:focus-within {
45
+ outline: 2px solid var(--ngp-focus-ring);
46
+ outline-offset: 2px;
47
+ }
48
+
49
+ [ngpNumberFieldInput] {
50
+ width: 64px;
51
+ height: 36px;
52
+ border: none;
53
+ outline: none;
54
+ text-align: center;
55
+ font-size: 0.875rem;
56
+ color: var(--ngp-text-primary);
57
+ background: transparent;
58
+ box-sizing: border-box;
59
+ padding: 0;
60
+ }
61
+
62
+ [ngpNumberFieldInput]::placeholder {
63
+ color: var(--ngp-text-placeholder);
64
+ }
65
+
66
+ [ngpNumberFieldIncrement],
67
+ [ngpNumberFieldDecrement] {
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ width: 36px;
72
+ height: 36px;
73
+ border: none;
74
+ background: transparent;
75
+ color: var(--ngp-text-secondary);
76
+ cursor: pointer;
77
+ font-size: 1rem;
78
+ user-select: none;
79
+ -webkit-touch-callout: none;
80
+ transition:
81
+ color 150ms ease,
82
+ background-color 150ms ease;
83
+ }
84
+
85
+ [ngpNumberFieldIncrement][data-hover],
86
+ [ngpNumberFieldDecrement][data-hover] {
87
+ background-color: var(--ngp-background-hover);
88
+ color: var(--ngp-text-primary);
89
+ }
90
+
91
+ [ngpNumberFieldIncrement][data-press],
92
+ [ngpNumberFieldDecrement][data-press] {
93
+ background-color: var(--ngp-background-active);
94
+ }
95
+
96
+ [ngpNumberFieldIncrement][data-disabled],
97
+ [ngpNumberFieldDecrement][data-disabled] {
98
+ opacity: 0.4;
99
+ cursor: not-allowed;
100
+ }
101
+
102
+ [ngpNumberFieldIncrement][data-disabled][data-hover],
103
+ [ngpNumberFieldDecrement][data-disabled][data-hover] {
104
+ background: transparent;
105
+ color: var(--ngp-text-secondary);
106
+ }
107
+ `,
108
+ })
109
+ export class NumberField<%= componentSuffix %> {}