ng-primitives 0.115.2 → 0.117.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.
@@ -1,22 +1,26 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, computed, input, booleanAttribute, output, Directive } from '@angular/core';
2
+ import { computed, input, booleanAttribute, output, Directive } from '@angular/core';
3
3
  import { ngpInteractions } from 'ng-primitives/interactions';
4
4
  import { injectElementRef } from 'ng-primitives/internal';
5
- import { createPrimitive, controlled, emitter, attrBinding, dataBinding, listener, deprecatedSetter } from 'ng-primitives/state';
5
+ import { createPrimitive, controlled, controlledState, attrBinding, dataBinding, listener, deprecatedSetter } from 'ng-primitives/state';
6
6
 
7
- const [NgpToggleStateToken, ngpToggle, injectToggleState, provideToggleState] = createPrimitive('NgpToggle', ({ selected: _selected = signal(false), disabled: _disabled = signal(false), onSelectedChange, }) => {
7
+ const [NgpToggleStateToken, ngpToggle, injectToggleState, provideToggleState] = createPrimitive('NgpToggle', ({ selected: _selected, defaultSelected: _defaultSelected, disabled: _disabled, onSelectedChange, }) => {
8
8
  const element = injectElementRef();
9
- const selected = controlled(_selected);
10
- const disabled = controlled(_disabled);
11
9
  const isButton = element.nativeElement.tagName.toLowerCase() === 'button';
12
- const selectedChange = emitter();
10
+ const defaultSelected = controlled(_defaultSelected, false);
11
+ const disabled = controlled(_disabled, false);
12
+ const tabindex = computed(() => (disabled() ? -1 : 0), ...(ngDevMode ? [{ debugName: "tabindex" }] : []));
13
+ const [selected, setSelected, selectedChange] = controlledState({
14
+ value: _selected,
15
+ defaultValue: defaultSelected,
16
+ onChange: onSelectedChange,
17
+ });
13
18
  ngpInteractions({
14
19
  hover: true,
15
20
  press: true,
16
21
  focusVisible: true,
17
22
  disabled,
18
23
  });
19
- const tabindex = computed(() => (disabled() ? -1 : 0), ...(ngDevMode ? [{ debugName: "tabindex" }] : []));
20
24
  // Host bindings
21
25
  attrBinding(element, 'type', () => (isButton ? 'button' : null));
22
26
  attrBinding(element, 'aria-pressed', selected);
@@ -41,20 +45,16 @@ const [NgpToggleStateToken, ngpToggle, injectToggleState, provideToggleState] =
41
45
  event?.preventDefault?.();
42
46
  setSelected(!selected());
43
47
  }
44
- function setSelected(value) {
45
- selected.set(value);
46
- onSelectedChange?.(value);
47
- selectedChange.emit(value);
48
- }
49
48
  function setDisabled(value) {
50
49
  disabled.set(value);
51
50
  }
52
51
  return {
53
- selected: deprecatedSetter(selected, 'setSelected'),
54
- disabled: deprecatedSetter(disabled, 'setDisabled'),
55
- selectedChange: selectedChange.asObservable(),
52
+ selected: deprecatedSetter(selected, 'setSelected', setSelected),
53
+ disabled: deprecatedSetter(disabled, 'setDisabled', setDisabled),
54
+ selectedChange,
56
55
  toggle,
57
56
  setSelected,
57
+ setDefaultSelected: defaultSelected.set,
58
58
  setDisabled,
59
59
  };
60
60
  });
@@ -66,13 +66,21 @@ class NgpToggle {
66
66
  constructor() {
67
67
  /**
68
68
  * Whether the toggle is selected.
69
- * @default false
70
69
  */
71
- this.selected = input(false, ...(ngDevMode ? [{ debugName: "selected", alias: 'ngpToggleSelected',
70
+ this.selected = input(undefined, ...(ngDevMode ? [{ debugName: "selected", alias: 'ngpToggleSelected',
72
71
  transform: booleanAttribute }] : [{
73
72
  alias: 'ngpToggleSelected',
74
73
  transform: booleanAttribute,
75
74
  }]));
75
+ /**
76
+ * The default selected state for uncontrolled usage.
77
+ * @default false
78
+ */
79
+ this.defaultSelected = input(false, ...(ngDevMode ? [{ debugName: "defaultSelected", alias: 'ngpToggleDefaultSelected',
80
+ transform: booleanAttribute }] : [{
81
+ alias: 'ngpToggleDefaultSelected',
82
+ transform: booleanAttribute,
83
+ }]));
76
84
  /**
77
85
  * Emits when the selected state changes.
78
86
  */
@@ -94,6 +102,7 @@ class NgpToggle {
94
102
  */
95
103
  this.state = ngpToggle({
96
104
  selected: this.selected,
105
+ defaultSelected: this.defaultSelected,
97
106
  disabled: this.disabled,
98
107
  onSelectedChange: value => this.selectedChange.emit(value),
99
108
  });
@@ -107,8 +116,14 @@ class NgpToggle {
107
116
  /**
108
117
  * Set the selected state.
109
118
  */
110
- setSelected(value) {
111
- this.state.setSelected(value);
119
+ setSelected(value, options) {
120
+ this.state.setSelected(value, options);
121
+ }
122
+ /**
123
+ * Set the default selected state.
124
+ */
125
+ setDefaultSelected(value) {
126
+ this.state.setDefaultSelected(value);
112
127
  }
113
128
  /*
114
129
  * Set the disabled state.
@@ -117,7 +132,7 @@ class NgpToggle {
117
132
  this.state.setDisabled(value);
118
133
  }
119
134
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpToggle, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
120
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpToggle, isStandalone: true, selector: "[ngpToggle]", inputs: { selected: { classPropertyName: "selected", publicName: "ngpToggleSelected", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "ngpToggleDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedChange: "ngpToggleSelectedChange" }, providers: [provideToggleState({ inherit: false })], exportAs: ["ngpToggle"], ngImport: i0 }); }
135
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpToggle, isStandalone: true, selector: "[ngpToggle]", inputs: { selected: { classPropertyName: "selected", publicName: "ngpToggleSelected", isSignal: true, isRequired: false, transformFunction: null }, defaultSelected: { classPropertyName: "defaultSelected", publicName: "ngpToggleDefaultSelected", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "ngpToggleDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedChange: "ngpToggleSelectedChange" }, providers: [provideToggleState({ inherit: false })], exportAs: ["ngpToggle"], ngImport: i0 }); }
121
136
  }
122
137
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpToggle, decorators: [{
123
138
  type: Directive,
@@ -126,7 +141,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
126
141
  exportAs: 'ngpToggle',
127
142
  providers: [provideToggleState({ inherit: false })],
128
143
  }]
129
- }], propDecorators: { selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpToggleSelected", required: false }] }], selectedChange: [{ type: i0.Output, args: ["ngpToggleSelectedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpToggleDisabled", required: false }] }] } });
144
+ }], propDecorators: { selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpToggleSelected", required: false }] }], defaultSelected: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpToggleDefaultSelected", required: false }] }], selectedChange: [{ type: i0.Output, args: ["ngpToggleSelectedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpToggleDisabled", required: false }] }] } });
130
145
 
131
146
  /**
132
147
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"ng-primitives-toggle.mjs","sources":["../../../../packages/ng-primitives/toggle/src/toggle/toggle-state.ts","../../../../packages/ng-primitives/toggle/src/toggle/toggle.ts","../../../../packages/ng-primitives/toggle/src/ng-primitives-toggle.ts"],"sourcesContent":["import { computed, Signal, signal, WritableSignal } from '@angular/core';\nimport { ngpInteractions } from 'ng-primitives/interactions';\nimport { injectElementRef } from 'ng-primitives/internal';\nimport {\n attrBinding,\n controlled,\n createPrimitive,\n dataBinding,\n deprecatedSetter,\n emitter,\n listener,\n} from 'ng-primitives/state';\nimport { Observable } from 'rxjs';\n\n/**\n * Public state surface for the Toggle primitive.\n */\nexport interface NgpToggleState {\n /**\n * Whether the toggle is selected.\n */\n readonly selected: WritableSignal<boolean>;\n /**\n * Whether the toggle is disabled.\n */\n readonly disabled: WritableSignal<boolean>;\n /**\n * Emits when the selected state changes.\n */\n readonly selectedChange: Observable<boolean>;\n /**\n * Toggle the selected state.\n */\n toggle(event?: Event): void;\n /**\n * Set the selected state.\n */\n setSelected(value: boolean): void;\n /**\n * Set the disabled state.\n */\n setDisabled(value: boolean): void;\n}\n\n/**\n * Inputs for configuring the Toggle primitive.\n */\nexport interface NgpToggleProps {\n /**\n * Whether the toggle is selected.\n */\n readonly selected?: Signal<boolean>;\n /**\n * Whether the toggle is disabled.\n */\n readonly disabled?: Signal<boolean>;\n /**\n * Callback fired when the selected state changes.\n */\n readonly onSelectedChange?: (selected: boolean) => void;\n}\n\nexport const [NgpToggleStateToken, ngpToggle, injectToggleState, provideToggleState] =\n createPrimitive(\n 'NgpToggle',\n ({\n selected: _selected = signal(false),\n disabled: _disabled = signal(false),\n onSelectedChange,\n }: NgpToggleProps): NgpToggleState => {\n const element = injectElementRef<HTMLElement>();\n const selected = controlled(_selected);\n const disabled = controlled(_disabled);\n const isButton = element.nativeElement.tagName.toLowerCase() === 'button';\n\n const selectedChange = emitter<boolean>();\n\n ngpInteractions({\n hover: true,\n press: true,\n focusVisible: true,\n disabled,\n });\n\n const tabindex = computed(() => (disabled() ? -1 : 0));\n\n // Host bindings\n attrBinding(element, 'type', () => (isButton ? 'button' : null));\n attrBinding(element, 'aria-pressed', selected);\n dataBinding(element, 'data-selected', selected);\n dataBinding(element, 'data-disabled', disabled);\n attrBinding(element, 'aria-disabled', disabled);\n attrBinding(element, 'tabindex', () => tabindex().toString());\n\n // Listeners\n listener(element, 'click', event => toggle(event));\n listener(element, 'keydown', (event: KeyboardEvent) => {\n if (event.key === ' ' || event.key === 'Spacebar') {\n if (!isButton && element.nativeElement.tagName !== 'a') {\n event.preventDefault();\n toggle(event);\n }\n }\n });\n\n function toggle(event?: Event): void {\n if (disabled()) {\n return;\n }\n\n event?.preventDefault?.();\n setSelected(!selected());\n }\n\n function setSelected(value: boolean): void {\n selected.set(value);\n onSelectedChange?.(value);\n selectedChange.emit(value);\n }\n\n function setDisabled(value: boolean): void {\n disabled.set(value);\n }\n\n return {\n selected: deprecatedSetter(selected, 'setSelected'),\n disabled: deprecatedSetter(disabled, 'setDisabled'),\n selectedChange: selectedChange.asObservable(),\n toggle,\n setSelected,\n setDisabled,\n } satisfies NgpToggleState;\n },\n );\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { booleanAttribute, Directive, input, output } from '@angular/core';\nimport { ngpToggle, provideToggleState } from './toggle-state';\n\n/**\n * Apply the `ngpToggle` directive to an element to manage the toggle state. This must be applied to a `button` element.\n */\n@Directive({\n selector: '[ngpToggle]',\n exportAs: 'ngpToggle',\n providers: [provideToggleState({ inherit: false })],\n})\nexport class NgpToggle {\n /**\n * Whether the toggle is selected.\n * @default false\n */\n readonly selected = input<boolean, BooleanInput>(false, {\n alias: 'ngpToggleSelected',\n transform: booleanAttribute,\n });\n\n /**\n * Emits when the selected state changes.\n */\n readonly selectedChange = output<boolean>({\n alias: 'ngpToggleSelectedChange',\n });\n\n /**\n * Whether the toggle is disabled.\n * @default false\n */\n readonly disabled = input<boolean, BooleanInput>(false, {\n alias: 'ngpToggleDisabled',\n transform: booleanAttribute,\n });\n\n /**\n * The state for the toggle primitive.\n * @internal\n */\n protected readonly state = ngpToggle({\n selected: this.selected,\n disabled: this.disabled,\n onSelectedChange: value => this.selectedChange.emit(value),\n });\n\n /**\n * Toggle the selected state.\n */\n toggle(): void {\n this.state.toggle();\n }\n\n /**\n * Set the selected state.\n */\n setSelected(value: boolean): void {\n this.state.setSelected(value);\n }\n\n /*\n * Set the disabled state.\n */\n setDisabled(value: boolean): void {\n this.state.setDisabled(value);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ng-primitives-toggle.mjs","sources":["../../../../packages/ng-primitives/toggle/src/toggle/toggle-state.ts","../../../../packages/ng-primitives/toggle/src/toggle/toggle.ts","../../../../packages/ng-primitives/toggle/src/ng-primitives-toggle.ts"],"sourcesContent":["import { computed, Signal, WritableSignal } from '@angular/core';\nimport { ngpInteractions } from 'ng-primitives/interactions';\nimport { injectElementRef } from 'ng-primitives/internal';\nimport {\n attrBinding,\n controlled,\n controlledState,\n createPrimitive,\n dataBinding,\n deprecatedSetter,\n listener,\n SetterOptions,\n} from 'ng-primitives/state';\nimport { Observable } from 'rxjs';\n\n/**\n * Public state surface for the Toggle primitive.\n */\nexport interface NgpToggleState {\n /**\n * Whether the toggle is selected.\n */\n readonly selected: WritableSignal<boolean>;\n /**\n * Whether the toggle is disabled.\n */\n readonly disabled: WritableSignal<boolean>;\n /**\n * Emits when the selected state changes.\n */\n readonly selectedChange: Observable<boolean>;\n /**\n * Toggle the selected state.\n */\n toggle(event?: Event): void;\n /**\n * Set the selected state.\n */\n setSelected(value: boolean, options?: SetterOptions): void;\n /**\n * Set the default selected state.\n */\n setDefaultSelected(value: boolean): void;\n /**\n * Set the disabled state.\n */\n setDisabled(value: boolean): void;\n}\n\n/**\n * Inputs for configuring the Toggle primitive.\n */\nexport interface NgpToggleProps {\n /**\n * Whether the toggle is selected.\n */\n readonly selected: Signal<boolean | undefined>;\n /**\n * The default selected state for uncontrolled usage.\n */\n readonly defaultSelected?: Signal<boolean>;\n /**\n * Whether the toggle is disabled.\n */\n readonly disabled?: Signal<boolean>;\n /**\n * Callback fired when the selected state changes.\n */\n readonly onSelectedChange?: (selected: boolean) => void;\n}\n\nexport const [NgpToggleStateToken, ngpToggle, injectToggleState, provideToggleState] =\n createPrimitive(\n 'NgpToggle',\n ({\n selected: _selected,\n defaultSelected: _defaultSelected,\n disabled: _disabled,\n onSelectedChange,\n }: NgpToggleProps): NgpToggleState => {\n const element = injectElementRef<HTMLElement>();\n\n const isButton = element.nativeElement.tagName.toLowerCase() === 'button';\n const defaultSelected = controlled(_defaultSelected, false);\n const disabled = controlled(_disabled, false);\n const tabindex = computed(() => (disabled() ? -1 : 0));\n\n const [selected, setSelected, selectedChange] = controlledState({\n value: _selected,\n defaultValue: defaultSelected,\n onChange: onSelectedChange,\n });\n\n ngpInteractions({\n hover: true,\n press: true,\n focusVisible: true,\n disabled,\n });\n\n // Host bindings\n attrBinding(element, 'type', () => (isButton ? 'button' : null));\n attrBinding(element, 'aria-pressed', selected);\n dataBinding(element, 'data-selected', selected);\n dataBinding(element, 'data-disabled', disabled);\n attrBinding(element, 'aria-disabled', disabled);\n attrBinding(element, 'tabindex', () => tabindex().toString());\n\n // Listeners\n listener(element, 'click', event => toggle(event));\n listener(element, 'keydown', (event: KeyboardEvent) => {\n if (event.key === ' ' || event.key === 'Spacebar') {\n if (!isButton && element.nativeElement.tagName !== 'a') {\n event.preventDefault();\n toggle(event);\n }\n }\n });\n\n function toggle(event?: Event): void {\n if (disabled()) {\n return;\n }\n\n event?.preventDefault?.();\n setSelected(!selected());\n }\n\n function setDisabled(value: boolean): void {\n disabled.set(value);\n }\n\n return {\n selected: deprecatedSetter(selected, 'setSelected', setSelected),\n disabled: deprecatedSetter(disabled, 'setDisabled', setDisabled),\n selectedChange,\n toggle,\n setSelected,\n setDefaultSelected: defaultSelected.set,\n setDisabled,\n } satisfies NgpToggleState;\n },\n );\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { booleanAttribute, Directive, input, output } from '@angular/core';\nimport { SetterOptions } from 'ng-primitives/state';\nimport { ngpToggle, provideToggleState } from './toggle-state';\n\n/**\n * Apply the `ngpToggle` directive to an element to manage the toggle state. This must be applied to a `button` element.\n */\n@Directive({\n selector: '[ngpToggle]',\n exportAs: 'ngpToggle',\n providers: [provideToggleState({ inherit: false })],\n})\nexport class NgpToggle {\n /**\n * Whether the toggle is selected.\n */\n readonly selected = input<boolean | undefined, BooleanInput>(undefined, {\n alias: 'ngpToggleSelected',\n transform: booleanAttribute,\n });\n\n /**\n * The default selected state for uncontrolled usage.\n * @default false\n */\n readonly defaultSelected = input<boolean, BooleanInput>(false, {\n alias: 'ngpToggleDefaultSelected',\n transform: booleanAttribute,\n });\n\n /**\n * Emits when the selected state changes.\n */\n readonly selectedChange = output<boolean>({\n alias: 'ngpToggleSelectedChange',\n });\n\n /**\n * Whether the toggle is disabled.\n * @default false\n */\n readonly disabled = input<boolean, BooleanInput>(false, {\n alias: 'ngpToggleDisabled',\n transform: booleanAttribute,\n });\n\n /**\n * The state for the toggle primitive.\n * @internal\n */\n protected readonly state = ngpToggle({\n selected: this.selected,\n defaultSelected: this.defaultSelected,\n disabled: this.disabled,\n onSelectedChange: value => this.selectedChange.emit(value),\n });\n\n /**\n * Toggle the selected state.\n */\n toggle(): void {\n this.state.toggle();\n }\n\n /**\n * Set the selected state.\n */\n setSelected(value: boolean, options?: SetterOptions): void {\n this.state.setSelected(value, options);\n }\n\n /**\n * Set the default selected state.\n */\n setDefaultSelected(value: boolean): void {\n this.state.setDefaultSelected(value);\n }\n\n /*\n * Set the disabled state.\n */\n setDisabled(value: boolean): void {\n this.state.setDisabled(value);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/menu/index.d.ts CHANGED
@@ -541,6 +541,26 @@ interface NgpMenuTriggerProps<T = unknown> {
541
541
  */
542
542
  readonly hideDelay?: Signal<number>;
543
543
  }
544
+ declare const NgpMenuTriggerStateToken: _angular_core.InjectionToken<WritableSignal<{
545
+ menu: WritableSignal<NgpOverlayContent<unknown> | undefined>;
546
+ placement: WritableSignal<NgpMenuPlacement>;
547
+ offset: WritableSignal<NgpOffset>;
548
+ disabled: WritableSignal<boolean>;
549
+ context: WritableSignal<unknown>;
550
+ open: Signal<boolean>;
551
+ openOrigin: WritableSignal<FocusOrigin>;
552
+ show: (origin?: FocusOrigin) => void;
553
+ hide: (origin?: FocusOrigin) => void;
554
+ toggle: (event: MouseEvent) => void;
555
+ setDisabled: (isDisabled: boolean) => void;
556
+ setMenu: (newMenu: NgpOverlayContent<unknown> | undefined) => void;
557
+ setFlip: (shouldFlip: NgpFlip) => void;
558
+ setPlacement: (newPlacement: NgpMenuPlacement) => void;
559
+ setOffset: (newOffset: NgpOffset) => void;
560
+ setContext: (newContext: unknown) => void;
561
+ setPointerOverContent: (isOver: boolean) => void;
562
+ flip: WritableSignal<NgpFlip>;
563
+ }>>;
544
564
  declare const ngpMenuTrigger: <T>({ disabled: _disabled, menu: _menu, placement: _placement, offset: _offset, flip: _flip, context: _context, container, scrollBehavior, cooldown, triggers, showDelay, hideDelay, }: NgpMenuTriggerProps<T>) => {
545
565
  menu: WritableSignal<NgpOverlayContent<T> | undefined>;
546
566
  placement: WritableSignal<NgpMenuPlacement>;
@@ -790,6 +810,25 @@ interface NgpSubmenuTriggerProps<T = unknown> {
790
810
  */
791
811
  readonly flip?: Signal<NgpFlip>;
792
812
  }
813
+ declare const NgpSubmenuTriggerStateToken: _angular_core.InjectionToken<WritableSignal<{
814
+ placement: WritableSignal<NgpMenuPlacement>;
815
+ offset: WritableSignal<NgpOffset>;
816
+ disabled: WritableSignal<boolean>;
817
+ menu: WritableSignal<NgpOverlayContent<unknown> | undefined>;
818
+ flip: WritableSignal<NgpFlip>;
819
+ open: Signal<boolean>;
820
+ openOrigin: WritableSignal<FocusOrigin>;
821
+ show: (origin?: FocusOrigin) => void;
822
+ hide: (origin?: FocusOrigin) => void;
823
+ toggle: (event: MouseEvent) => void;
824
+ setDisabled: (isDisabled: boolean) => void;
825
+ setMenu: (newMenu: NgpOverlayContent<unknown> | undefined) => void;
826
+ setFlip: (shouldFlip: NgpFlip) => void;
827
+ setPlacement: (newPlacement: NgpMenuPlacement) => void;
828
+ setOffset: (newOffset: NgpOffset) => void;
829
+ focus: (origin: FocusOrigin) => void;
830
+ setPointerOverContent: (_isOver: boolean) => void;
831
+ }>>;
793
832
  declare const ngpSubmenuTrigger: <T>({ disabled: _disabled, menu: _menu, placement: _placement, offset: _offset, flip: _flip, }: NgpSubmenuTriggerProps<T>) => {
794
833
  placement: WritableSignal<NgpMenuPlacement>;
795
834
  offset: WritableSignal<NgpOffset>;
@@ -898,5 +937,5 @@ declare const provideSubmenuTriggerState: (opts?: {
898
937
  inherit?: boolean;
899
938
  }) => _angular_core.FactoryProvider;
900
939
 
901
- export { NgpMenu, NgpMenuItem, NgpMenuItemCheckbox, NgpMenuItemIndicator, NgpMenuItemRadio, NgpMenuItemRadioGroup, NgpMenuTrigger, NgpSubmenuTrigger, injectMenuItemCheckboxState, injectMenuItemRadioGroupState, injectMenuItemRadioState, injectMenuItemState, injectMenuState, injectMenuTriggerState, injectSubmenuTriggerState, ngpMenu, ngpMenuItem, ngpMenuItemCheckbox, ngpMenuItemRadio, ngpMenuItemRadioGroup, ngpMenuTrigger, ngpSubmenuTrigger, provideMenuConfig, provideMenuItemCheckboxState, provideMenuItemRadioGroupState, provideMenuItemRadioState, provideMenuItemState, provideMenuState, provideMenuTriggerState, provideSubmenuTriggerState };
940
+ export { NgpMenu, NgpMenuItem, NgpMenuItemCheckbox, NgpMenuItemIndicator, NgpMenuItemRadio, NgpMenuItemRadioGroup, NgpMenuTrigger, NgpMenuTriggerStateToken, NgpSubmenuTrigger, NgpSubmenuTriggerStateToken, injectMenuItemCheckboxState, injectMenuItemRadioGroupState, injectMenuItemRadioState, injectMenuItemState, injectMenuState, injectMenuTriggerState, injectSubmenuTriggerState, ngpMenu, ngpMenuItem, ngpMenuItemCheckbox, ngpMenuItemRadio, ngpMenuItemRadioGroup, ngpMenuTrigger, ngpSubmenuTrigger, provideMenuConfig, provideMenuItemCheckboxState, provideMenuItemRadioGroupState, provideMenuItemRadioState, provideMenuItemState, provideMenuState, provideMenuTriggerState, provideSubmenuTriggerState };
902
941
  export type { NgpMenuConfig, NgpMenuItemCheckboxProps, NgpMenuItemCheckboxState, NgpMenuItemProps, NgpMenuItemRadioGroupProps, NgpMenuItemRadioGroupState, NgpMenuItemRadioProps, NgpMenuItemRadioState, NgpMenuItemState, NgpMenuPlacement, NgpMenuProps, NgpMenuState, NgpMenuTriggerProps, NgpMenuTriggerState, NgpSubmenuTriggerProps, NgpSubmenuTriggerState };
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.115.2",
5
+ "version": "0.117.0",
6
6
  "keywords": [
7
7
  "angular",
8
8
  "primitives",
@@ -104,6 +104,10 @@
104
104
  "types": "./common/index.d.ts",
105
105
  "default": "./fesm2022/ng-primitives-common.mjs"
106
106
  },
107
+ "./context-menu": {
108
+ "types": "./context-menu/index.d.ts",
109
+ "default": "./fesm2022/ng-primitives-context-menu.mjs"
110
+ },
107
111
  "./date-picker": {
108
112
  "types": "./date-picker/index.d.ts",
109
113
  "default": "./fesm2022/ng-primitives-date-picker.mjs"
package/portal/index.d.ts CHANGED
@@ -248,6 +248,11 @@ interface NgpOverlayConfig<T = unknown> {
248
248
  * Use with trackPosition for smooth cursor following.
249
249
  */
250
250
  position?: Signal<NgpPosition | null>;
251
+ /**
252
+ * If true, clicks on the trigger element count as outside clicks for dismiss purposes.
253
+ * Useful for context menus where the trigger area is large and clicks on it should dismiss the menu.
254
+ */
255
+ treatTriggerClickAsOutside?: boolean;
251
256
  /**
252
257
  * Overlay type identifier for cooldown grouping.
253
258
  * When set, overlays of the same type share a cooldown period.
@@ -544,6 +549,8 @@ interface NgpOverlayEntry {
544
549
  anchorElement?: HTMLElement | null;
545
550
  /** Per-instance dismiss configuration */
546
551
  dismissPolicy: NgpDismissPolicy;
552
+ /** If true, clicks on the trigger element are treated as outside clicks */
553
+ treatTriggerClickAsOutside?: boolean;
547
554
  /** Optional subject that receives pointer events that occur outside the overlay */
548
555
  outsidePointerEvents$?: Subject<MouseEvent>;
549
556
  }
@@ -0,0 +1,41 @@
1
+ import { Component } from '@angular/core';
2
+ import { NgpContextMenuItem } from 'ng-primitives/context-menu';
3
+
4
+ @Component({
5
+ selector: 'button[<%= prefix %>-context-menu-item]',
6
+ hostDirectives: [NgpContextMenuItem],
7
+ host: { type: 'button' },
8
+ template: `
9
+ <ng-content />
10
+ `,
11
+ styles: `
12
+ /* These styles rely on CSS variables that can be imported from ng-primitives/example-theme/index.css in your global styles */
13
+
14
+ :host {
15
+ display: flex;
16
+ align-items: center;
17
+ justify-content: space-between;
18
+ padding: 6px 8px 6px 14px;
19
+ border: none;
20
+ background: none;
21
+ cursor: pointer;
22
+ transition: background-color 0.2s;
23
+ border-radius: 4px;
24
+ min-width: 120px;
25
+ text-align: start;
26
+ outline: none;
27
+ font-size: 14px;
28
+ font-weight: 400;
29
+ }
30
+
31
+ :host[data-hover] {
32
+ background-color: var(--ngp-background-active);
33
+ }
34
+
35
+ :host[data-focus-visible] {
36
+ outline: 2px solid var(--ngp-focus-ring);
37
+ z-index: 1;
38
+ }
39
+ `,
40
+ })
41
+ export class ContextMenuItem<%= componentSuffix %> {}
@@ -0,0 +1,54 @@
1
+ import { Component } from '@angular/core';
2
+ import { NgpContextMenu } from 'ng-primitives/context-menu';
3
+
4
+ @Component({
5
+ selector: '<%= prefix %>-context-menu',
6
+ hostDirectives: [NgpContextMenu],
7
+ template: `
8
+ <ng-content />
9
+ `,
10
+ styles: `
11
+ /* These styles rely on CSS variables that can be imported from ng-primitives/example-theme/index.css in your global styles */
12
+
13
+ :host {
14
+ position: fixed;
15
+ display: flex;
16
+ flex-direction: column;
17
+ width: max-content;
18
+ background: var(--ngp-background);
19
+ border: 1px solid var(--ngp-border);
20
+ box-shadow: var(--ngp-shadow);
21
+ border-radius: 8px;
22
+ padding: 4px;
23
+ transform-origin: var(--ngp-menu-transform-origin);
24
+ animation: menu-show 300ms ease-out;
25
+ }
26
+
27
+ :host[data-exit] {
28
+ animation: menu-hide 300ms ease-out;
29
+ }
30
+
31
+ @keyframes menu-show {
32
+ 0% {
33
+ opacity: 0;
34
+ transform: scale(0.9);
35
+ }
36
+ 100% {
37
+ opacity: 1;
38
+ transform: scale(1);
39
+ }
40
+ }
41
+
42
+ @keyframes menu-hide {
43
+ 0% {
44
+ opacity: 1;
45
+ transform: scale(1);
46
+ }
47
+ 100% {
48
+ opacity: 0;
49
+ transform: scale(0.9);
50
+ }
51
+ }
52
+ `,
53
+ })
54
+ export class ContextMenu<%= componentSuffix %> {}
@@ -77,7 +77,7 @@ export class Toggle<%= componentSuffix %> implements ControlValueAccessor {
77
77
 
78
78
  /** Write a new value to the toggle. */
79
79
  writeValue(value: boolean): void {
80
- this.toggle().setSelected(value);
80
+ this.toggle().setSelected(value, { emit: false });
81
81
  }
82
82
 
83
83
  /** Register a callback function to be called when the value changes. */
@@ -58,7 +58,7 @@ export class ToggleGroup<%= componentSuffix %> implements ControlValueAccessor {
58
58
 
59
59
  /** Write a new value to the toggle group. */
60
60
  writeValue(value: string[]): void {
61
- this.toggleGroup().setValue(value);
61
+ this.toggleGroup().setValue(value, { emit: false });
62
62
  }
63
63
 
64
64
  /** Register a callback function to be called when the value changes. */
package/state/index.d.ts CHANGED
@@ -93,6 +93,36 @@ declare function createPrimitive<TFactory extends (...args: any[]) => unknown>(n
93
93
  }) => FactoryProvider
94
94
  ];
95
95
  declare function controlled<T>(value: Signal<T>): WritableSignal<T>;
96
+ declare function controlled<T>(value: Signal<T> | undefined, defaultValue: T): WritableSignal<T>;
97
+ interface ControlledStateOptions<T> {
98
+ /**
99
+ * The controlled value signal. When defined (not `undefined`), the component
100
+ * is in controlled mode and this value always wins.
101
+ */
102
+ readonly value: Signal<T | undefined>;
103
+ /**
104
+ * The default value signal for uncontrolled mode.
105
+ */
106
+ readonly defaultValue?: Signal<T>;
107
+ /**
108
+ * Callback fired when the value changes.
109
+ */
110
+ readonly onChange?: (value: T) => void;
111
+ }
112
+ interface SetterOptions {
113
+ /**
114
+ * Whether to fire `onChange` and emit on the `change` observable.
115
+ * Defaults to `true`. Set to `false` for cases like form `writeValue`
116
+ * where the internal state should sync without notifying listeners.
117
+ */
118
+ readonly emit?: boolean;
119
+ }
120
+ type ControlledState<T> = [
121
+ value: Signal<T>,
122
+ set: (value: T, options?: SetterOptions) => void,
123
+ change: Observable<T>
124
+ ];
125
+ declare function controlledState<T>({ value, onChange, defaultValue, }: ControlledStateOptions<T>): ControlledState<T>;
96
126
  declare function attrBinding(element: ElementRef<HTMLElement>, attr: string, value: (() => string | number | boolean | null | undefined) | string | number | boolean | null | undefined): void;
97
127
  declare function styleBinding(element: ElementRef<HTMLElement>, style: string, value: (() => string | number | null) | string | number | null): void;
98
128
  declare function dataBinding(element: ElementRef<HTMLElement>, attr: string, value: (() => string | boolean | null) | string | boolean | null): void;
@@ -112,6 +142,7 @@ declare function onDestroy(callback: () => void): void;
112
142
  * signal and returns a proxy that warns the user when set is called directly.
113
143
  */
114
144
  declare function deprecatedSetter<T>(signal: WritableSignal<T>, methodName: string): WritableSignal<T>;
145
+ declare function deprecatedSetter<T>(signal: Signal<T>, methodName: string, setter: (value: T) => void): WritableSignal<T>;
115
146
  /**
116
147
  * A utility function to inject an inherited state from a parent injector. This is useful for cases
117
148
  * where a primitive needs to inherit state from a parent primitive, such as in roving focus groups.
@@ -131,5 +162,5 @@ declare function emitter<T>({ injector, }?: {
131
162
  injector?: Injector;
132
163
  }): Emitter<T>;
133
164
 
134
- export { attrBinding, controlled, createPrimitive, createState, createStateInjector, createStateProvider, createStateToken, dataBinding, deprecatedSetter, emitter, injectInheritedState, listener, onDestroy, onMount, styleBinding };
135
- export type { CreatePrimitiveOptions, CreateStateProviderOptions, CreatedState, Emitter, InjectedState, State };
165
+ export { attrBinding, controlled, controlledState, createPrimitive, createState, createStateInjector, createStateProvider, createStateToken, dataBinding, deprecatedSetter, emitter, injectInheritedState, listener, onDestroy, onMount, styleBinding };
166
+ export type { ControlledState, ControlledStateOptions, CreatePrimitiveOptions, CreateStateProviderOptions, CreatedState, Emitter, InjectedState, SetterOptions, State };
package/toggle/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { WritableSignal, Signal } from '@angular/core';
3
+ import { SetterOptions } from 'ng-primitives/state';
3
4
  import { Observable } from 'rxjs';
4
5
  import { BooleanInput } from '@angular/cdk/coercion';
5
6
 
@@ -26,7 +27,11 @@ interface NgpToggleState {
26
27
  /**
27
28
  * Set the selected state.
28
29
  */
29
- setSelected(value: boolean): void;
30
+ setSelected(value: boolean, options?: SetterOptions): void;
31
+ /**
32
+ * Set the default selected state.
33
+ */
34
+ setDefaultSelected(value: boolean): void;
30
35
  /**
31
36
  * Set the disabled state.
32
37
  */
@@ -39,7 +44,11 @@ interface NgpToggleProps {
39
44
  /**
40
45
  * Whether the toggle is selected.
41
46
  */
42
- readonly selected?: Signal<boolean>;
47
+ readonly selected: Signal<boolean | undefined>;
48
+ /**
49
+ * The default selected state for uncontrolled usage.
50
+ */
51
+ readonly defaultSelected?: Signal<boolean>;
43
52
  /**
44
53
  * Whether the toggle is disabled.
45
54
  */
@@ -49,7 +58,7 @@ interface NgpToggleProps {
49
58
  */
50
59
  readonly onSelectedChange?: (selected: boolean) => void;
51
60
  }
52
- declare const ngpToggle: ({ selected: _selected, disabled: _disabled, onSelectedChange, }: NgpToggleProps) => NgpToggleState;
61
+ declare const ngpToggle: ({ selected: _selected, defaultSelected: _defaultSelected, disabled: _disabled, onSelectedChange, }: NgpToggleProps) => NgpToggleState;
53
62
  declare const injectToggleState: {
54
63
  (): Signal<NgpToggleState>;
55
64
  (options: {
@@ -73,9 +82,13 @@ declare const provideToggleState: (opts?: {
73
82
  declare class NgpToggle {
74
83
  /**
75
84
  * Whether the toggle is selected.
85
+ */
86
+ readonly selected: _angular_core.InputSignalWithTransform<boolean | undefined, BooleanInput>;
87
+ /**
88
+ * The default selected state for uncontrolled usage.
76
89
  * @default false
77
90
  */
78
- readonly selected: _angular_core.InputSignalWithTransform<boolean, BooleanInput>;
91
+ readonly defaultSelected: _angular_core.InputSignalWithTransform<boolean, BooleanInput>;
79
92
  /**
80
93
  * Emits when the selected state changes.
81
94
  */
@@ -97,10 +110,14 @@ declare class NgpToggle {
97
110
  /**
98
111
  * Set the selected state.
99
112
  */
100
- setSelected(value: boolean): void;
113
+ setSelected(value: boolean, options?: SetterOptions): void;
114
+ /**
115
+ * Set the default selected state.
116
+ */
117
+ setDefaultSelected(value: boolean): void;
101
118
  setDisabled(value: boolean): void;
102
119
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgpToggle, never>;
103
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgpToggle, "[ngpToggle]", ["ngpToggle"], { "selected": { "alias": "ngpToggleSelected"; "required": false; "isSignal": true; }; "disabled": { "alias": "ngpToggleDisabled"; "required": false; "isSignal": true; }; }, { "selectedChange": "ngpToggleSelectedChange"; }, never, never, true, never>;
120
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgpToggle, "[ngpToggle]", ["ngpToggle"], { "selected": { "alias": "ngpToggleSelected"; "required": false; "isSignal": true; }; "defaultSelected": { "alias": "ngpToggleDefaultSelected"; "required": false; "isSignal": true; }; "disabled": { "alias": "ngpToggleDisabled"; "required": false; "isSignal": true; }; }, { "selectedChange": "ngpToggleSelectedChange"; }, never, never, true, never>;
104
121
  }
105
122
 
106
123
  export { NgpToggle, injectToggleState, ngpToggle, provideToggleState };
@@ -3,6 +3,7 @@ import { Provider, OnInit, Signal, WritableSignal } from '@angular/core';
3
3
  import { NgpOrientation } from 'ng-primitives/common';
4
4
  import { BooleanInput } from '@angular/cdk/coercion';
5
5
  import { NgpRovingFocusGroupState } from 'ng-primitives/roving-focus';
6
+ import { SetterOptions } from 'ng-primitives/state';
6
7
  import { Observable } from 'rxjs';
7
8
 
8
9
  interface NgpToggleGroupConfig {
@@ -127,7 +128,11 @@ interface NgpToggleGroupState {
127
128
  /**
128
129
  * Set the value(s) of the toggle group.
129
130
  */
130
- setValue(newValue: string[]): void;
131
+ setValue(newValue: string[], options?: SetterOptions): void;
132
+ /**
133
+ * Set the default value(s) of the toggle group.
134
+ */
135
+ setDefaultValue(defaultValue: string[]): void;
131
136
  /**
132
137
  * Set the disabled state of the toggle group.
133
138
  */
@@ -160,7 +165,11 @@ interface NgpToggleGroupProps {
160
165
  /**
161
166
  * The value(s) of the toggle-group.
162
167
  */
163
- readonly value?: Signal<string[] | undefined>;
168
+ readonly value: Signal<string[] | undefined>;
169
+ /**
170
+ * The default value(s) of the toggle-group for uncontrolled usage.
171
+ */
172
+ readonly defaultValue?: Signal<string[]>;
164
173
  /**
165
174
  * Whether the toggle-group is disabled.
166
175
  */
@@ -170,7 +179,7 @@ interface NgpToggleGroupProps {
170
179
  */
171
180
  readonly onValueChange?: (value: string[]) => void;
172
181
  }
173
- declare const ngpToggleGroup: ({ rovingFocusGroup, orientation: _orientation, allowDeselection, type, value: _value, disabled: _disabled, onValueChange, }: NgpToggleGroupProps) => NgpToggleGroupState;
182
+ declare const ngpToggleGroup: ({ rovingFocusGroup, orientation: _orientation, allowDeselection: _allowDeselection, type: _type, value: _value, defaultValue: _defaultValue, disabled: _disabled, onValueChange, }: NgpToggleGroupProps) => NgpToggleGroupState;
174
183
  declare const injectToggleGroupState: {
175
184
  (): Signal<NgpToggleGroupState>;
176
185
  (options: {
@@ -214,7 +223,12 @@ declare class NgpToggleGroup {
214
223
  /**
215
224
  * The selected value(s) of the toggle group.
216
225
  */
217
- readonly value: _angular_core.InputSignal<string[]>;
226
+ readonly value: _angular_core.InputSignal<string[] | undefined>;
227
+ /**
228
+ * The default selected value(s) for uncontrolled usage.
229
+ * @default []
230
+ */
231
+ readonly defaultValue: _angular_core.InputSignal<string[]>;
218
232
  /**
219
233
  * Emits when the value of the toggle group changes.
220
234
  */
@@ -234,7 +248,11 @@ declare class NgpToggleGroup {
234
248
  /**
235
249
  * Set the value(s) of the toggle group.
236
250
  */
237
- setValue(newValue: string[]): void;
251
+ setValue(newValue: string[], options?: SetterOptions): void;
252
+ /**
253
+ * Set the default value(s) of the toggle group.
254
+ */
255
+ setDefaultValue(defaultValue: string[]): void;
238
256
  /**
239
257
  * Set the disabled state of the toggle group.
240
258
  */
@@ -244,7 +262,7 @@ declare class NgpToggleGroup {
244
262
  */
245
263
  setOrientation(newOrientation: NgpOrientation): void;
246
264
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgpToggleGroup, never>;
247
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgpToggleGroup, "[ngpToggleGroup]", ["ngpToggleGroup"], { "orientation": { "alias": "ngpToggleGroupOrientation"; "required": false; "isSignal": true; }; "wrap": { "alias": "ngpToggleGroupWrap"; "required": false; "isSignal": true; }; "allowDeselection": { "alias": "ngpToggleGroupAllowDeselection"; "required": false; "isSignal": true; }; "type": { "alias": "ngpToggleGroupType"; "required": false; "isSignal": true; }; "value": { "alias": "ngpToggleGroupValue"; "required": false; "isSignal": true; }; "disabled": { "alias": "ngpToggleGroupDisabled"; "required": false; "isSignal": true; }; }, { "valueChange": "ngpToggleGroupValueChange"; }, never, never, true, never>;
265
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgpToggleGroup, "[ngpToggleGroup]", ["ngpToggleGroup"], { "orientation": { "alias": "ngpToggleGroupOrientation"; "required": false; "isSignal": true; }; "wrap": { "alias": "ngpToggleGroupWrap"; "required": false; "isSignal": true; }; "allowDeselection": { "alias": "ngpToggleGroupAllowDeselection"; "required": false; "isSignal": true; }; "type": { "alias": "ngpToggleGroupType"; "required": false; "isSignal": true; }; "value": { "alias": "ngpToggleGroupValue"; "required": false; "isSignal": true; }; "defaultValue": { "alias": "ngpToggleGroupDefaultValue"; "required": false; "isSignal": true; }; "disabled": { "alias": "ngpToggleGroupDisabled"; "required": false; "isSignal": true; }; }, { "valueChange": "ngpToggleGroupValueChange"; }, never, never, true, never>;
248
266
  }
249
267
 
250
268
  export { NgpToggleGroup, NgpToggleGroupItem, injectToggleGroupItemState, injectToggleGroupState, ngpToggleGroup, ngpToggleGroupItem, provideToggleGroupConfig, provideToggleGroupItemState, provideToggleGroupState };