@spartan-ng/brain 0.0.1-alpha.719 → 1.0.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.
Files changed (39) hide show
  1. package/README.md +3 -3
  2. package/fesm2022/spartan-ng-brain-accordion.mjs +7 -58
  3. package/fesm2022/spartan-ng-brain-accordion.mjs.map +1 -1
  4. package/fesm2022/spartan-ng-brain-alert-dialog.mjs +1 -2
  5. package/fesm2022/spartan-ng-brain-alert-dialog.mjs.map +1 -1
  6. package/fesm2022/spartan-ng-brain-autocomplete.mjs +3 -1
  7. package/fesm2022/spartan-ng-brain-autocomplete.mjs.map +1 -1
  8. package/fesm2022/spartan-ng-brain-collapsible.mjs +8 -56
  9. package/fesm2022/spartan-ng-brain-collapsible.mjs.map +1 -1
  10. package/fesm2022/spartan-ng-brain-combobox.mjs +22 -6
  11. package/fesm2022/spartan-ng-brain-combobox.mjs.map +1 -1
  12. package/fesm2022/spartan-ng-brain-core.mjs +89 -16
  13. package/fesm2022/spartan-ng-brain-core.mjs.map +1 -1
  14. package/fesm2022/spartan-ng-brain-dialog.mjs +8 -7
  15. package/fesm2022/spartan-ng-brain-dialog.mjs.map +1 -1
  16. package/fesm2022/spartan-ng-brain-drawer.mjs +8 -8
  17. package/fesm2022/spartan-ng-brain-drawer.mjs.map +1 -1
  18. package/fesm2022/spartan-ng-brain-field.mjs +7 -2
  19. package/fesm2022/spartan-ng-brain-field.mjs.map +1 -1
  20. package/fesm2022/spartan-ng-brain-navigation-menu.mjs +124 -34
  21. package/fesm2022/spartan-ng-brain-navigation-menu.mjs.map +1 -1
  22. package/fesm2022/spartan-ng-brain-overlay.mjs +27 -14
  23. package/fesm2022/spartan-ng-brain-overlay.mjs.map +1 -1
  24. package/fesm2022/spartan-ng-brain-select.mjs +3 -1
  25. package/fesm2022/spartan-ng-brain-select.mjs.map +1 -1
  26. package/fesm2022/spartan-ng-brain-tooltip.mjs +97 -14
  27. package/fesm2022/spartan-ng-brain-tooltip.mjs.map +1 -1
  28. package/package.json +6 -2
  29. package/types/spartan-ng-brain-accordion.d.ts +4 -22
  30. package/types/spartan-ng-brain-autocomplete.d.ts +1 -0
  31. package/types/spartan-ng-brain-collapsible.d.ts +5 -22
  32. package/types/spartan-ng-brain-combobox.d.ts +11 -2
  33. package/types/spartan-ng-brain-core.d.ts +40 -9
  34. package/types/spartan-ng-brain-dialog.d.ts +1 -3
  35. package/types/spartan-ng-brain-drawer.d.ts +3 -3
  36. package/types/spartan-ng-brain-navigation-menu.d.ts +9 -2
  37. package/types/spartan-ng-brain-overlay.d.ts +4 -5
  38. package/types/spartan-ng-brain-select.d.ts +1 -0
  39. package/types/spartan-ng-brain-tooltip.d.ts +38 -4
@@ -1,4 +1,4 @@
1
- import { untracked, computed, InjectionToken, forwardRef, inject, runInInjectionContext, Injector, ElementRef, PLATFORM_ID, DestroyRef, signal, afterNextRender } from '@angular/core';
1
+ import { untracked, computed, InjectionToken, forwardRef, inject, ElementRef, PLATFORM_ID, DestroyRef, signal, afterNextRender, runInInjectionContext, Injector } from '@angular/core';
2
2
  import { Observable, pipe, merge, fromEvent } from 'rxjs';
3
3
  import { map, filter, distinctUntilChanged, takeUntil, debounceTime } from 'rxjs/operators';
4
4
  import { toObservable, toSignal } from '@angular/core/rxjs-interop';
@@ -119,6 +119,60 @@ const [injectExposedSideProvider, provideExposedSideProvider, provideExposedSide
119
119
 
120
120
  const [injectExposesStateProvider, provideExposesStateProvider, provideExposesStateProviderExisting, EXPOSES_STATE_TOKEN,] = createInjectionToken('@spartan-ng EXPOSES_STATE_TOKEN');
121
121
 
122
+ /**
123
+ * Measures the natural size of a collapsible host's content via `scrollHeight` so it can animate
124
+ * between `height: 0` and a measured pixel height - the whole content is covered, regardless of how
125
+ * it is projected. A `ResizeObserver` on the content keeps the value live. SSR-safe; the host must
126
+ * be a block-level element for `scrollHeight` to reflect its content.
127
+ *
128
+ * @returns Signals with the content's width and height in px, or `null` before measurement.
129
+ */
130
+ function injectContentDimensions() {
131
+ const host = inject(ElementRef).nativeElement;
132
+ const platformId = inject(PLATFORM_ID);
133
+ const destroyRef = inject(DestroyRef);
134
+ const width = signal(null, ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
135
+ const height = signal(null, ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
136
+ if (isPlatformServer(platformId)) {
137
+ return { width: width.asReadonly(), height: height.asReadonly() };
138
+ }
139
+ const measure = () => {
140
+ // Drop the clamped height for the read: scrollHeight is never smaller than the element's own
141
+ // height, so while clamped it would only ever grow. `height: auto` lets it reflect the real
142
+ // content size (and shrink). The read is synchronous, so the swap never paints.
143
+ const previousHeight = host.style.height;
144
+ host.style.height = 'auto';
145
+ width.set(host.scrollWidth);
146
+ height.set(host.scrollHeight);
147
+ host.style.height = previousHeight;
148
+ };
149
+ afterNextRender({
150
+ read: () => {
151
+ measure();
152
+ if (typeof ResizeObserver === 'undefined')
153
+ return;
154
+ // Observe the content wrapper (not the clamped/animated host) so re-measures fire on content
155
+ // changes, never on the open/close height animation. Re-measure on a fresh frame rather than
156
+ // inside the callback: measure() mutates the host's inline height, and doing that during
157
+ // delivery trips "ResizeObserver loop completed with undelivered notifications".
158
+ let frame = 0;
159
+ const observer = new ResizeObserver(() => {
160
+ cancelAnimationFrame(frame);
161
+ frame = requestAnimationFrame(measure);
162
+ });
163
+ const content = host.firstElementChild;
164
+ if (content) {
165
+ observer.observe(content);
166
+ }
167
+ destroyRef.onDestroy(() => {
168
+ cancelAnimationFrame(frame);
169
+ observer.disconnect();
170
+ });
171
+ },
172
+ });
173
+ return { width: width.asReadonly(), height: height.asReadonly() };
174
+ }
175
+
122
176
  /**
123
177
  * Returns a reactive signal that tracks the size of a DOM element.
124
178
  *
@@ -197,21 +251,18 @@ function getSharedObserver() {
197
251
  return sharedObserver;
198
252
  }
199
253
 
200
- const measureDimensions = (elementToMeasure, measurementDisplay) => {
201
- const previousHeight = elementToMeasure.style.height;
202
- const previousDisplay = elementToMeasure.style.display;
203
- const previousHidden = elementToMeasure.hidden;
204
- elementToMeasure.hidden = false;
205
- elementToMeasure.style.height = 'auto';
206
- elementToMeasure.style.display =
207
- !previousDisplay || previousDisplay === 'none' ? measurementDisplay : previousDisplay;
208
- const { width, height } = elementToMeasure.getBoundingClientRect();
209
- elementToMeasure.hidden = previousHidden;
210
- elementToMeasure.style.display = previousDisplay;
211
- elementToMeasure.style.height = previousHeight;
212
- return { width, height };
254
+ const OPPOSITE_SIDE = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' };
255
+ const MENU_SIDE = new InjectionToken('SpartanMenuSide');
256
+ // derive data-side from the transform-origin CDK sets on the content. the anchored corner faces the
257
+ // trigger, so the side is its opposite. the configured `side` tells us which axis carries the anchor
258
+ // (top/bottom -> vertical token, left/right -> horizontal), so a CDK flip is read off the right axis.
259
+ // CDK's origin is rtl-aware, so the derived side is too. falls back to the configured side when the
260
+ // transform-origin is missing or centered (no flip information to apply).
261
+ const deriveMenuSideFromTransformOrigin = (transformOrigin, side) => {
262
+ const [x, y] = transformOrigin.trim().split(/\s+/);
263
+ const anchor = side === 'top' || side === 'bottom' ? y : x;
264
+ return OPPOSITE_SIDE[anchor] ?? side;
213
265
  };
214
-
215
266
  const createMenuPosition = (align, side) => {
216
267
  const verticalAlign = align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center';
217
268
  const createPositions = (originX, originY, overlayX, overlayY) => [
@@ -259,6 +310,28 @@ function serializeValue(value) {
259
310
  }
260
311
  }
261
312
 
313
+ /** Must be called in an injection context; cleans up its pending timer on destroy. */
314
+ function injectSkipDelay(skipDelayDuration) {
315
+ const isOpenDelayed = signal(true, ...(ngDevMode ? [{ debugName: "isOpenDelayed" }] : /* istanbul ignore next */ []));
316
+ let timer;
317
+ inject(DestroyRef).onDestroy(() => clearTimeout(timer));
318
+ return {
319
+ isOpenDelayed: isOpenDelayed.asReadonly(),
320
+ open() {
321
+ clearTimeout(timer);
322
+ if (skipDelayDuration() > 0)
323
+ isOpenDelayed.set(false);
324
+ },
325
+ close() {
326
+ clearTimeout(timer);
327
+ const duration = skipDelayDuration();
328
+ if (duration > 0) {
329
+ timer = setTimeout(() => isOpenDelayed.set(true), duration);
330
+ }
331
+ },
332
+ };
333
+ }
334
+
262
335
  const [injectTableClassesSettable, provideTableClassesSettable, provideTableClassesSettableExisting, SET_TABLE_CLASSES_TOKEN,] = createInjectionToken('@spartan-ng SET_TABLE_CLASSES_TOKEN');
263
336
 
264
337
  const MAX_ANIMATION_WAIT_MS = 5_000;
@@ -308,5 +381,5 @@ function getFallbackTimeout(animations) {
308
381
  * Generated bundle index. Do not edit.
309
382
  */
310
383
 
311
- export { EXPOSES_SIDE_TOKEN, EXPOSES_STATE_TOKEN, SET_CLASS_TO_CUSTOM_ELEMENT_TOKEN, SET_TABLE_CLASSES_TOKEN, brnDevMode, brnZoneFree, brnZoneFull, brnZoneOptimized, computedPrevious, createHoverObservable, createMenuPosition, cssClassesToArray, debouncedSignal, getActiveElementAnimations, injectCustomClassSettable, injectElementSize, injectExposedSideProvider, injectExposesStateProvider, injectTableClassesSettable, isElement, measureDimensions, provideCustomClassSettable, provideCustomClassSettableExisting, provideExposedSideProvider, provideExposedSideProviderExisting, provideExposesStateProvider, provideExposesStateProviderExisting, provideTableClassesSettable, provideTableClassesSettableExisting, serializeValue, stringifyAsLabel, waitForAnimations, waitForElementAnimations };
384
+ export { EXPOSES_SIDE_TOKEN, EXPOSES_STATE_TOKEN, MENU_SIDE, SET_CLASS_TO_CUSTOM_ELEMENT_TOKEN, SET_TABLE_CLASSES_TOKEN, brnDevMode, brnZoneFree, brnZoneFull, brnZoneOptimized, computedPrevious, createHoverObservable, createMenuPosition, cssClassesToArray, debouncedSignal, deriveMenuSideFromTransformOrigin, getActiveElementAnimations, injectContentDimensions, injectCustomClassSettable, injectElementSize, injectExposedSideProvider, injectExposesStateProvider, injectSkipDelay, injectTableClassesSettable, isElement, provideCustomClassSettable, provideCustomClassSettableExisting, provideExposedSideProvider, provideExposedSideProviderExisting, provideExposesStateProvider, provideExposesStateProviderExisting, provideTableClassesSettable, provideTableClassesSettableExisting, serializeValue, stringifyAsLabel, waitForAnimations, waitForElementAnimations };
312
385
  //# sourceMappingURL=spartan-ng-brain-core.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"spartan-ng-brain-core.mjs","sources":["../../../../libs/brain/core/src/helpers/computed-previous.ts","../../../../libs/brain/core/src/helpers/zone-free.ts","../../../../libs/brain/core/src/helpers/create-hover-observable.ts","../../../../libs/brain/core/src/helpers/css-classes-to-array.ts","../../../../libs/brain/core/src/helpers/create-injection-token.ts","../../../../libs/brain/core/src/helpers/custom-element-class-settable.ts","../../../../libs/brain/core/src/helpers/debounced-signal.ts","../../../../libs/brain/core/src/helpers/dev-mode.ts","../../../../libs/brain/core/src/helpers/exposes-side.ts","../../../../libs/brain/core/src/helpers/exposes-state.ts","../../../../libs/brain/core/src/helpers/inject-element-size.ts","../../../../libs/brain/core/src/helpers/measure-dimensions.ts","../../../../libs/brain/core/src/helpers/menu-align.ts","../../../../libs/brain/core/src/helpers/resolve-value-label.ts","../../../../libs/brain/core/src/helpers/table-classes-settable.ts","../../../../libs/brain/core/src/helpers/wait-for-element-animations.ts","../../../../libs/brain/core/src/spartan-ng-brain-core.ts"],"sourcesContent":["import { computed, type Signal, untracked } from '@angular/core';\n\n/**\n * Returns a signal that emits the previous value of the given signal.\n * The first time the signal is emitted, the previous value will be the same as the current value.\n *\n * @example\n * ```ts\n * const value = signal(0);\n * const previous = computedPrevious(value);\n *\n * effect(() => {\n * console.log('Current value:', value());\n * console.log('Previous value:', previous());\n * });\n *\n * Logs:\n * // Current value: 0\n * // Previous value: 0\n *\n * value.set(1);\n *\n * Logs:\n * // Current value: 1\n * // Previous value: 0\n *\n * value.set(2);\n *\n * Logs:\n * // Current value: 2\n * // Previous value: 1\n *```\n *\n * @param computation Signal to compute previous value for\n * @returns Signal that emits previous value of `s`\n */\nexport function computedPrevious<T>(computation: Signal<T>): Signal<T> {\n\tlet current = null as T;\n\tlet previous = untracked(() => computation()); // initial value is the current value\n\n\treturn computed(() => {\n\t\tcurrent = computation();\n\t\tconst result = previous;\n\t\tprevious = current;\n\t\treturn result;\n\t});\n}\n","/**\n * We are building on shoulders of giants here and use the implementation provided by the incredible TaigaUI\n * team: https://github.com/taiga-family/taiga-ui/blob/main/projects/cdk/observables/zone-free.ts#L22\n * Check them out! Give them a try! Leave a star! Their work is incredible!\n */\nimport type { NgZone } from '@angular/core';\nimport { type MonoTypeOperatorFunction, Observable, pipe } from 'rxjs';\n\nexport function brnZoneFull<T>(zone: NgZone): MonoTypeOperatorFunction<T> {\n\treturn (source) =>\n\t\tnew Observable((subscriber) =>\n\t\t\tsource.subscribe({\n\t\t\t\tnext: (value) => zone.run(() => subscriber.next(value)),\n\t\t\t\terror: (error: unknown) => zone.run(() => subscriber.error(error)),\n\t\t\t\tcomplete: () => zone.run(() => subscriber.complete()),\n\t\t\t}),\n\t\t);\n}\n\nexport function brnZoneFree<T>(zone: NgZone): MonoTypeOperatorFunction<T> {\n\treturn (source) => new Observable((subscriber) => zone.runOutsideAngular(() => source.subscribe(subscriber)));\n}\n\nexport function brnZoneOptimized<T>(zone: NgZone): MonoTypeOperatorFunction<T> {\n\treturn pipe(brnZoneFree(zone), brnZoneFull(zone));\n}\n","import type { NgZone } from '@angular/core';\nimport { type Observable, type Subject, fromEvent, merge } from 'rxjs';\nimport { distinctUntilChanged, filter, map, takeUntil } from 'rxjs/operators';\nimport { brnZoneOptimized } from './zone-free';\n\nfunction movedOut({ currentTarget, relatedTarget }: MouseEvent): boolean {\n\treturn !isElement(relatedTarget) || !isElement(currentTarget) || !currentTarget.contains(relatedTarget);\n}\n\nexport function isElement(node?: Element | EventTarget | Node | null): node is Element {\n\treturn !!node && 'nodeType' in node && node.nodeType === Node.ELEMENT_NODE;\n}\n\nexport const createHoverObservable = (\n\tnativeElement: HTMLElement,\n\tzone: NgZone,\n\tdestroyed$: Subject<void>,\n): Observable<{ hover: boolean; relatedTarget?: EventTarget | null }> => {\n\treturn merge(\n\t\tfromEvent(nativeElement, 'mouseenter').pipe(map(() => ({ hover: true }))),\n\t\tfromEvent<MouseEvent>(nativeElement, 'mouseleave').pipe(\n\t\t\tmap((e) => ({ hover: false, relatedTarget: e.relatedTarget })),\n\t\t),\n\t\t// Hello, Safari\n\t\tfromEvent<MouseEvent>(nativeElement, 'mouseout').pipe(\n\t\t\tfilter(movedOut),\n\t\t\tmap((e) => ({ hover: false, relatedTarget: e.relatedTarget })),\n\t\t),\n\t).pipe(distinctUntilChanged(), brnZoneOptimized(zone), takeUntil(destroyed$));\n};\n","export function cssClassesToArray(classes: string | string[] | null | undefined, defaultClass = ''): string[] {\n\tconst value = classes ?? defaultClass;\n\treturn (Array.isArray(value) ? value : [value]).flatMap((className) => className.split(/\\s+/).filter(Boolean));\n}\n","import { type InjectOptions, InjectionToken, type Provider, type Type, forwardRef, inject } from '@angular/core';\n\ntype InjectFn<TTokenValue> = {\n\t(): TTokenValue;\n\t(injectOptions: InjectOptions & { optional?: false }): TTokenValue;\n\t(injectOptions: InjectOptions & { optional: true }): TTokenValue | null;\n};\n\ntype ProvideFn<TTokenValue> = (value: TTokenValue) => Provider;\n\ntype ProvideExistingFn<TTokenValue> = (valueFactory: () => Type<TTokenValue>) => Provider;\n\nexport type CreateInjectionTokenReturn<TTokenValue> = [\n\tInjectFn<TTokenValue>,\n\tProvideFn<TTokenValue>,\n\tProvideExistingFn<TTokenValue>,\n\tInjectionToken<TTokenValue>,\n];\n\nexport function createInjectionToken<TTokenValue>(description: string): CreateInjectionTokenReturn<TTokenValue> {\n\tconst token = new InjectionToken<TTokenValue>(description);\n\n\tconst provideFn = (value: TTokenValue) => {\n\t\treturn { provide: token, useValue: value };\n\t};\n\n\tconst provideExistingFn = (value: () => TTokenValue) => {\n\t\treturn { provide: token, useExisting: forwardRef(value) };\n\t};\n\n\tconst injectFn = (options: InjectOptions = {}) => {\n\t\treturn inject(token, options);\n\t};\n\n\treturn [injectFn, provideFn, provideExistingFn, token] as CreateInjectionTokenReturn<TTokenValue>;\n}\n","import { createInjectionToken } from './create-injection-token';\n\nexport interface CustomElementClassSettable {\n\tsetClassToCustomElement: (newClass: string) => void;\n}\n\nexport const [\n\tinjectCustomClassSettable,\n\tprovideCustomClassSettable,\n\tprovideCustomClassSettableExisting,\n\tSET_CLASS_TO_CUSTOM_ELEMENT_TOKEN,\n] = createInjectionToken<CustomElementClassSettable>('@spartan-ng SET_CLASS_TO_CUSTOM_ELEMENT_TOKEN');\n","import type { Signal } from '@angular/core';\nimport { toObservable, toSignal } from '@angular/core/rxjs-interop';\nimport { debounceTime, distinctUntilChanged } from 'rxjs/operators';\n\n/**\n * Creates a debounced version of a source signal.\n *\n * @param source - The input signal to debounce.\n * @param delay - Debounce time in milliseconds.\n * @returns A new signal that updates only after the source has stopped changing for `delay` ms.\n */\nexport function debouncedSignal<T>(source: Signal<T>, delay: number): Signal<T> {\n\tconst source$ = toObservable(source);\n\n\tconst debounced$ = source$.pipe(debounceTime(delay), distinctUntilChanged());\n\n\treturn toSignal(debounced$, { initialValue: source() });\n}\n","declare const ngDevMode: boolean;\n/**\n * Set by Angular to true when in development mode.\n * Allows for tree-shaking code that is only used in development.\n */\nexport const brnDevMode = ngDevMode;\n","import type { Signal } from '@angular/core';\nimport { createInjectionToken } from './create-injection-token';\n\nexport interface ExposesSide {\n\tside: Signal<'top' | 'bottom' | 'left' | 'right'>;\n}\n\nexport const [\n\tinjectExposedSideProvider,\n\tprovideExposedSideProvider,\n\tprovideExposedSideProviderExisting,\n\tEXPOSES_SIDE_TOKEN,\n] = createInjectionToken<ExposesSide>('@spartan-ng EXPOSES_SIDE_TOKEN');\n","import type { Signal } from '@angular/core';\nimport { createInjectionToken } from './create-injection-token';\n\nexport interface ExposesState {\n\tstate: Signal<'open' | 'closed'>;\n}\n\nexport const [\n\tinjectExposesStateProvider,\n\tprovideExposesStateProvider,\n\tprovideExposesStateProviderExisting,\n\tEXPOSES_STATE_TOKEN,\n] = createInjectionToken<ExposesState>('@spartan-ng EXPOSES_STATE_TOKEN');\n","import { isPlatformServer } from '@angular/common';\nimport {\n\tafterNextRender,\n\tDestroyRef,\n\tElementRef,\n\tinject,\n\tInjector,\n\tPLATFORM_ID,\n\trunInInjectionContext,\n\ttype Signal,\n\tsignal,\n\ttype WritableSignal,\n} from '@angular/core';\n\n/**\n * Returns a reactive signal that tracks the size of a DOM element.\n *\n * This function uses a shared {@link ResizeObserver} internally to monitor multiple elements efficiently.\n * The returned signal updates whenever the element's width or height changes. It is fully SSR-safe.\n *\n * @param options Optional {@link ElementSizeOptions} configuration object.\n * @param options.elementRef The {@link ElementRef} of the element to observe. Defaults to the {@link ElementRef} injected in the current context.\n * @param options.injector Optional custom {@link Injector} to run the function in. Defaults to the current injection context.\n *\n * @returns A readonly {@link Signal} containing `{ width, height }` of the element, or `undefined` if the element has not yet been measured or on the server.\n *\n * Based on https://github.com/radix-ui/primitives/blob/main/packages/react/use-size/src/use-size.tsx\n */\nexport function injectElementSize(\n\toptions: ElementSizeOptions = {},\n): Signal<{ width: number; height: number } | undefined> {\n\treturn runInInjectionContext(options.injector ?? inject(Injector), () => {\n\t\tconst elementRef = options.elementRef ?? inject(ElementRef);\n\t\tconst platformId = inject(PLATFORM_ID);\n\t\tconst destroyRef = inject(DestroyRef);\n\n\t\tconst element = elementRef.nativeElement;\n\t\tconst size = signal<{ width: number; height: number } | undefined>(undefined);\n\n\t\tif (isPlatformServer(platformId)) {\n\t\t\treturn size;\n\t\t}\n\n\t\tafterNextRender({\n\t\t\tread: () => {\n\t\t\t\t// Initial read\n\t\t\t\tconst rect = element.getBoundingClientRect();\n\t\t\t\tsize.set({\n\t\t\t\t\twidth: rect.width || element.offsetWidth,\n\t\t\t\t\theight: rect.height || element.offsetHeight,\n\t\t\t\t});\n\n\t\t\t\t// Register element in shared observer\n\t\t\t\tobserverMap.set(element, { element, size });\n\t\t\t\tgetSharedObserver().observe(element, { box: 'border-box' });\n\n\t\t\t\tdestroyRef.onDestroy(() => {\n\t\t\t\t\tgetSharedObserver().unobserve(element);\n\t\t\t\t\tobserverMap.delete(element);\n\n\t\t\t\t\t// Disconnect global observer if no elements left\n\t\t\t\t\tif (observerMap.size === 0 && sharedObserver) {\n\t\t\t\t\t\tsharedObserver.disconnect();\n\t\t\t\t\t\tsharedObserver = undefined;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t});\n\n\t\treturn size.asReadonly();\n\t});\n}\n\nconst observerMap = new Map<HTMLElement, SizeEntry>();\nlet sharedObserver: ResizeObserver | undefined;\n\nfunction getSharedObserver() {\n\tif (!sharedObserver) {\n\t\tsharedObserver = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tconst el = entry.target as HTMLElement;\n\t\t\t\tconst entryData = observerMap.get(el);\n\t\t\t\tif (!entryData) continue;\n\n\t\t\t\tlet width: number;\n\t\t\t\tlet height: number;\n\n\t\t\t\tif ('borderBoxSize' in entry) {\n\t\t\t\t\t// Iron out differences between browsers\n\t\t\t\t\tconst borderSize = Array.isArray(entry.borderBoxSize) ? entry.borderBoxSize[0] : entry.borderBoxSize;\n\t\t\t\t\twidth = borderSize.inlineSize;\n\t\t\t\t\theight = borderSize.blockSize;\n\t\t\t\t} else {\n\t\t\t\t\twidth = el.offsetWidth;\n\t\t\t\t\theight = el.offsetHeight;\n\t\t\t\t}\n\n\t\t\t\tentryData.size.set({ width, height });\n\t\t\t}\n\t\t});\n\t}\n\n\treturn sharedObserver;\n}\n\n/**\n * Options to configure `injectElementSize`.\n */\ninterface ElementSizeOptions {\n\t/** The ElementRef of the element to observe. Defaults to injected ElementRef in the current context. */\n\telementRef?: ElementRef<HTMLElement>;\n\t/** Optional Injector to run the function in. Defaults to the current injection context. */\n\tinjector?: Injector;\n}\n\n/**\n * Internal type used to track each observed element in the shared ResizeObserver.\n */\ninterface SizeEntry {\n\t/** The HTML element being observed. */\n\telement: HTMLElement;\n\t/** Writable signal storing the element's current width and height. */\n\tsize: WritableSignal<{ width: number; height: number } | undefined>;\n}\n","export type MeasurementDisplay = 'block' | 'inline-block' | 'flex' | 'grid' | 'table' | 'contents' | (string & {});\n\nexport const measureDimensions = (elementToMeasure: HTMLElement, measurementDisplay: MeasurementDisplay) => {\n\tconst previousHeight = elementToMeasure.style.height;\n\tconst previousDisplay = elementToMeasure.style.display;\n\tconst previousHidden = elementToMeasure.hidden;\n\n\telementToMeasure.hidden = false;\n\telementToMeasure.style.height = 'auto';\n\telementToMeasure.style.display =\n\t\t!previousDisplay || previousDisplay === 'none' ? measurementDisplay : previousDisplay;\n\n\tconst { width, height } = elementToMeasure.getBoundingClientRect();\n\n\telementToMeasure.hidden = previousHidden;\n\telementToMeasure.style.display = previousDisplay;\n\telementToMeasure.style.height = previousHeight;\n\n\treturn { width, height };\n};\n","import type { ConnectedPosition } from '@angular/cdk/overlay';\n\nexport type MenuAlign = 'start' | 'center' | 'end';\nexport type MenuSide = 'top' | 'bottom' | 'left' | 'right';\n\nexport const createMenuPosition = (align: MenuAlign, side: MenuSide): ConnectedPosition[] => {\n\tconst verticalAlign = align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center';\n\n\tconst createPositions = (\n\t\toriginX: 'start' | 'center' | 'end',\n\t\toriginY: 'top' | 'center' | 'bottom',\n\t\toverlayX: 'start' | 'center' | 'end',\n\t\toverlayY: 'top' | 'center' | 'bottom',\n\t): ConnectedPosition[] => [\n\t\t{ originX, originY, overlayX, overlayY },\n\t\t{ originX: overlayX, originY: overlayY, overlayX: originX, overlayY: originY },\n\t];\n\n\tswitch (side) {\n\t\tcase 'top':\n\t\t\treturn createPositions(align, 'top', align, 'bottom');\n\t\tcase 'bottom':\n\t\t\treturn createPositions(align, 'bottom', align, 'top');\n\t\tcase 'left':\n\t\t\treturn createPositions('start', verticalAlign, 'end', verticalAlign);\n\t\tcase 'right':\n\t\t\treturn createPositions('end', verticalAlign, 'start', verticalAlign);\n\t}\n};\n","export function stringifyAsLabel(item: any, itemToStringLabel?: (item: any) => string) {\n\tif (itemToStringLabel && item !== null && item !== undefined) {\n\t\treturn itemToStringLabel(item) ?? '';\n\t}\n\tif (item && typeof item === 'object') {\n\t\tif ('label' in item && item.label !== null && item.label !== undefined) {\n\t\t\treturn String(item.label);\n\t\t}\n\t\tif ('value' in item && item.value !== null && item.value !== undefined) {\n\t\t\treturn String(item.value);\n\t\t}\n\t}\n\treturn serializeValue(item);\n}\n\nexport function serializeValue(value: unknown): string {\n\tif (value === null || value === undefined) {\n\t\treturn '';\n\t}\n\tif (typeof value === 'string') {\n\t\treturn value;\n\t}\n\ttry {\n\t\treturn JSON.stringify(value);\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n","import { createInjectionToken } from './create-injection-token';\n\nexport interface TableClassesSettable {\n\tsetTableClasses: (classes: Partial<{ table: string; headerRow: string; bodyRow: string }>) => void;\n}\n\nexport const [\n\tinjectTableClassesSettable,\n\tprovideTableClassesSettable,\n\tprovideTableClassesSettableExisting,\n\tSET_TABLE_CLASSES_TOKEN,\n] = createInjectionToken<TableClassesSettable>('@spartan-ng SET_TABLE_CLASSES_TOKEN');\n","const MAX_ANIMATION_WAIT_MS = 5_000;\nconst ANIMATION_WAIT_BUFFER_MS = 50;\n\nexport function getActiveElementAnimations(elements: readonly (HTMLElement | null | undefined)[]): Animation[] {\n\treturn elements\n\t\t.filter((element): element is HTMLElement => !!element)\n\t\t.flatMap((element) =>\n\t\t\ttypeof element.getAnimations === 'function'\n\t\t\t\t? element.getAnimations({ subtree: true }).filter((animation) => animation.playState !== 'finished')\n\t\t\t\t: [],\n\t\t);\n}\n\nexport async function waitForAnimations(animations: readonly Animation[]): Promise<void> {\n\tif (!animations.length) return;\n\n\tlet timeout: ReturnType<typeof setTimeout> | undefined;\n\tconst fallbackMs = getFallbackTimeout(animations);\n\n\ttry {\n\t\tawait Promise.race([\n\t\t\tPromise.allSettled(animations.map((animation) => animation.finished)),\n\t\t\tnew Promise<void>((resolve) => {\n\t\t\t\ttimeout = setTimeout(resolve, fallbackMs);\n\t\t\t}),\n\t\t]);\n\t} finally {\n\t\tif (timeout) clearTimeout(timeout);\n\t}\n}\n\n/**\n * Waits for active animations, including subtree animations, within the given element to finish.\n */\nexport async function waitForElementAnimations(element: HTMLElement): Promise<void> {\n\tawait waitForAnimations(getActiveElementAnimations([element]));\n}\n\nfunction getFallbackTimeout(animations: readonly Animation[]): number {\n\tconst longestAnimation = animations.reduce((longest, animation) => {\n\t\tconst endTime = animation.effect?.getComputedTiming().endTime;\n\t\treturn typeof endTime === 'number' && Number.isFinite(endTime) ? Math.max(longest, endTime) : longest;\n\t}, 0);\n\n\tif (!longestAnimation) return MAX_ANIMATION_WAIT_MS;\n\treturn Math.min(longestAnimation + ANIMATION_WAIT_BUFFER_MS, MAX_ANIMATION_WAIT_MS);\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":"spartan-ng-brain-core.mjs","sources":["../../../../libs/brain/core/src/helpers/computed-previous.ts","../../../../libs/brain/core/src/helpers/zone-free.ts","../../../../libs/brain/core/src/helpers/create-hover-observable.ts","../../../../libs/brain/core/src/helpers/css-classes-to-array.ts","../../../../libs/brain/core/src/helpers/create-injection-token.ts","../../../../libs/brain/core/src/helpers/custom-element-class-settable.ts","../../../../libs/brain/core/src/helpers/debounced-signal.ts","../../../../libs/brain/core/src/helpers/dev-mode.ts","../../../../libs/brain/core/src/helpers/exposes-side.ts","../../../../libs/brain/core/src/helpers/exposes-state.ts","../../../../libs/brain/core/src/helpers/inject-content-dimensions.ts","../../../../libs/brain/core/src/helpers/inject-element-size.ts","../../../../libs/brain/core/src/helpers/menu-align.ts","../../../../libs/brain/core/src/helpers/resolve-value-label.ts","../../../../libs/brain/core/src/helpers/skip-delay.ts","../../../../libs/brain/core/src/helpers/table-classes-settable.ts","../../../../libs/brain/core/src/helpers/wait-for-element-animations.ts","../../../../libs/brain/core/src/spartan-ng-brain-core.ts"],"sourcesContent":["import { computed, type Signal, untracked } from '@angular/core';\n\n/**\n * Returns a signal that emits the previous value of the given signal.\n * The first time the signal is emitted, the previous value will be the same as the current value.\n *\n * @example\n * ```ts\n * const value = signal(0);\n * const previous = computedPrevious(value);\n *\n * effect(() => {\n * console.log('Current value:', value());\n * console.log('Previous value:', previous());\n * });\n *\n * Logs:\n * // Current value: 0\n * // Previous value: 0\n *\n * value.set(1);\n *\n * Logs:\n * // Current value: 1\n * // Previous value: 0\n *\n * value.set(2);\n *\n * Logs:\n * // Current value: 2\n * // Previous value: 1\n *```\n *\n * @param computation Signal to compute previous value for\n * @returns Signal that emits previous value of `s`\n */\nexport function computedPrevious<T>(computation: Signal<T>): Signal<T> {\n\tlet current = null as T;\n\tlet previous = untracked(() => computation()); // initial value is the current value\n\n\treturn computed(() => {\n\t\tcurrent = computation();\n\t\tconst result = previous;\n\t\tprevious = current;\n\t\treturn result;\n\t});\n}\n","/**\n * We are building on shoulders of giants here and use the implementation provided by the incredible TaigaUI\n * team: https://github.com/taiga-family/taiga-ui/blob/main/projects/cdk/observables/zone-free.ts#L22\n * Check them out! Give them a try! Leave a star! Their work is incredible!\n */\nimport type { NgZone } from '@angular/core';\nimport { type MonoTypeOperatorFunction, Observable, pipe } from 'rxjs';\n\nexport function brnZoneFull<T>(zone: NgZone): MonoTypeOperatorFunction<T> {\n\treturn (source) =>\n\t\tnew Observable((subscriber) =>\n\t\t\tsource.subscribe({\n\t\t\t\tnext: (value) => zone.run(() => subscriber.next(value)),\n\t\t\t\terror: (error: unknown) => zone.run(() => subscriber.error(error)),\n\t\t\t\tcomplete: () => zone.run(() => subscriber.complete()),\n\t\t\t}),\n\t\t);\n}\n\nexport function brnZoneFree<T>(zone: NgZone): MonoTypeOperatorFunction<T> {\n\treturn (source) => new Observable((subscriber) => zone.runOutsideAngular(() => source.subscribe(subscriber)));\n}\n\nexport function brnZoneOptimized<T>(zone: NgZone): MonoTypeOperatorFunction<T> {\n\treturn pipe(brnZoneFree(zone), brnZoneFull(zone));\n}\n","import type { NgZone } from '@angular/core';\nimport { type Observable, type Subject, fromEvent, merge } from 'rxjs';\nimport { distinctUntilChanged, filter, map, takeUntil } from 'rxjs/operators';\nimport { brnZoneOptimized } from './zone-free';\n\nfunction movedOut({ currentTarget, relatedTarget }: MouseEvent): boolean {\n\treturn !isElement(relatedTarget) || !isElement(currentTarget) || !currentTarget.contains(relatedTarget);\n}\n\nexport function isElement(node?: Element | EventTarget | Node | null): node is Element {\n\treturn !!node && 'nodeType' in node && node.nodeType === Node.ELEMENT_NODE;\n}\n\nexport const createHoverObservable = (\n\tnativeElement: HTMLElement,\n\tzone: NgZone,\n\tdestroyed$: Subject<void>,\n): Observable<{ hover: boolean; relatedTarget?: EventTarget | null }> => {\n\treturn merge(\n\t\tfromEvent(nativeElement, 'mouseenter').pipe(map(() => ({ hover: true }))),\n\t\tfromEvent<MouseEvent>(nativeElement, 'mouseleave').pipe(\n\t\t\tmap((e) => ({ hover: false, relatedTarget: e.relatedTarget })),\n\t\t),\n\t\t// Hello, Safari\n\t\tfromEvent<MouseEvent>(nativeElement, 'mouseout').pipe(\n\t\t\tfilter(movedOut),\n\t\t\tmap((e) => ({ hover: false, relatedTarget: e.relatedTarget })),\n\t\t),\n\t).pipe(distinctUntilChanged(), brnZoneOptimized(zone), takeUntil(destroyed$));\n};\n","export function cssClassesToArray(classes: string | string[] | null | undefined, defaultClass = ''): string[] {\n\tconst value = classes ?? defaultClass;\n\treturn (Array.isArray(value) ? value : [value]).flatMap((className) => className.split(/\\s+/).filter(Boolean));\n}\n","import { type InjectOptions, InjectionToken, type Provider, type Type, forwardRef, inject } from '@angular/core';\n\ntype InjectFn<TTokenValue> = {\n\t(): TTokenValue;\n\t(injectOptions: InjectOptions & { optional?: false }): TTokenValue;\n\t(injectOptions: InjectOptions & { optional: true }): TTokenValue | null;\n};\n\ntype ProvideFn<TTokenValue> = (value: TTokenValue) => Provider;\n\ntype ProvideExistingFn<TTokenValue> = (valueFactory: () => Type<TTokenValue>) => Provider;\n\nexport type CreateInjectionTokenReturn<TTokenValue> = [\n\tInjectFn<TTokenValue>,\n\tProvideFn<TTokenValue>,\n\tProvideExistingFn<TTokenValue>,\n\tInjectionToken<TTokenValue>,\n];\n\nexport function createInjectionToken<TTokenValue>(description: string): CreateInjectionTokenReturn<TTokenValue> {\n\tconst token = new InjectionToken<TTokenValue>(description);\n\n\tconst provideFn = (value: TTokenValue) => {\n\t\treturn { provide: token, useValue: value };\n\t};\n\n\tconst provideExistingFn = (value: () => TTokenValue) => {\n\t\treturn { provide: token, useExisting: forwardRef(value) };\n\t};\n\n\tconst injectFn = (options: InjectOptions = {}) => {\n\t\treturn inject(token, options);\n\t};\n\n\treturn [injectFn, provideFn, provideExistingFn, token] as CreateInjectionTokenReturn<TTokenValue>;\n}\n","import { createInjectionToken } from './create-injection-token';\n\nexport interface CustomElementClassSettable {\n\tsetClassToCustomElement: (newClass: string) => void;\n}\n\nexport const [\n\tinjectCustomClassSettable,\n\tprovideCustomClassSettable,\n\tprovideCustomClassSettableExisting,\n\tSET_CLASS_TO_CUSTOM_ELEMENT_TOKEN,\n] = createInjectionToken<CustomElementClassSettable>('@spartan-ng SET_CLASS_TO_CUSTOM_ELEMENT_TOKEN');\n","import type { Signal } from '@angular/core';\nimport { toObservable, toSignal } from '@angular/core/rxjs-interop';\nimport { debounceTime, distinctUntilChanged } from 'rxjs/operators';\n\n/**\n * Creates a debounced version of a source signal.\n *\n * @param source - The input signal to debounce.\n * @param delay - Debounce time in milliseconds.\n * @returns A new signal that updates only after the source has stopped changing for `delay` ms.\n */\nexport function debouncedSignal<T>(source: Signal<T>, delay: number): Signal<T> {\n\tconst source$ = toObservable(source);\n\n\tconst debounced$ = source$.pipe(debounceTime(delay), distinctUntilChanged());\n\n\treturn toSignal(debounced$, { initialValue: source() });\n}\n","declare const ngDevMode: boolean;\n/**\n * Set by Angular to true when in development mode.\n * Allows for tree-shaking code that is only used in development.\n */\nexport const brnDevMode = ngDevMode;\n","import type { Signal } from '@angular/core';\nimport { createInjectionToken } from './create-injection-token';\n\nexport interface ExposesSide {\n\tside: Signal<'top' | 'bottom' | 'left' | 'right'>;\n}\n\nexport const [\n\tinjectExposedSideProvider,\n\tprovideExposedSideProvider,\n\tprovideExposedSideProviderExisting,\n\tEXPOSES_SIDE_TOKEN,\n] = createInjectionToken<ExposesSide>('@spartan-ng EXPOSES_SIDE_TOKEN');\n","import type { Signal } from '@angular/core';\nimport { createInjectionToken } from './create-injection-token';\n\nexport interface ExposesState {\n\tstate: Signal<'open' | 'closed'>;\n}\n\nexport const [\n\tinjectExposesStateProvider,\n\tprovideExposesStateProvider,\n\tprovideExposesStateProviderExisting,\n\tEXPOSES_STATE_TOKEN,\n] = createInjectionToken<ExposesState>('@spartan-ng EXPOSES_STATE_TOKEN');\n","import { isPlatformServer } from '@angular/common';\nimport { afterNextRender, DestroyRef, ElementRef, inject, PLATFORM_ID, type Signal, signal } from '@angular/core';\n\n/** Reactive natural size of a collapsible host's projected content, or `null` before measurement. */\nexport interface ContentDimensions {\n\twidth: Signal<number | null>;\n\theight: Signal<number | null>;\n}\n\n/**\n * Measures the natural size of a collapsible host's content via `scrollHeight` so it can animate\n * between `height: 0` and a measured pixel height - the whole content is covered, regardless of how\n * it is projected. A `ResizeObserver` on the content keeps the value live. SSR-safe; the host must\n * be a block-level element for `scrollHeight` to reflect its content.\n *\n * @returns Signals with the content's width and height in px, or `null` before measurement.\n */\nexport function injectContentDimensions(): ContentDimensions {\n\tconst host = inject(ElementRef).nativeElement as HTMLElement;\n\tconst platformId = inject(PLATFORM_ID);\n\tconst destroyRef = inject(DestroyRef);\n\n\tconst width = signal<number | null>(null);\n\tconst height = signal<number | null>(null);\n\n\tif (isPlatformServer(platformId)) {\n\t\treturn { width: width.asReadonly(), height: height.asReadonly() };\n\t}\n\n\tconst measure = (): void => {\n\t\t// Drop the clamped height for the read: scrollHeight is never smaller than the element's own\n\t\t// height, so while clamped it would only ever grow. `height: auto` lets it reflect the real\n\t\t// content size (and shrink). The read is synchronous, so the swap never paints.\n\t\tconst previousHeight = host.style.height;\n\t\thost.style.height = 'auto';\n\t\twidth.set(host.scrollWidth);\n\t\theight.set(host.scrollHeight);\n\t\thost.style.height = previousHeight;\n\t};\n\n\tafterNextRender({\n\t\tread: () => {\n\t\t\tmeasure();\n\t\t\tif (typeof ResizeObserver === 'undefined') return;\n\n\t\t\t// Observe the content wrapper (not the clamped/animated host) so re-measures fire on content\n\t\t\t// changes, never on the open/close height animation. Re-measure on a fresh frame rather than\n\t\t\t// inside the callback: measure() mutates the host's inline height, and doing that during\n\t\t\t// delivery trips \"ResizeObserver loop completed with undelivered notifications\".\n\t\t\tlet frame = 0;\n\t\t\tconst observer = new ResizeObserver(() => {\n\t\t\t\tcancelAnimationFrame(frame);\n\t\t\t\tframe = requestAnimationFrame(measure);\n\t\t\t});\n\t\t\tconst content = host.firstElementChild;\n\t\t\tif (content) {\n\t\t\t\tobserver.observe(content);\n\t\t\t}\n\t\t\tdestroyRef.onDestroy(() => {\n\t\t\t\tcancelAnimationFrame(frame);\n\t\t\t\tobserver.disconnect();\n\t\t\t});\n\t\t},\n\t});\n\n\treturn { width: width.asReadonly(), height: height.asReadonly() };\n}\n","import { isPlatformServer } from '@angular/common';\nimport {\n\tafterNextRender,\n\tDestroyRef,\n\tElementRef,\n\tinject,\n\tInjector,\n\tPLATFORM_ID,\n\trunInInjectionContext,\n\ttype Signal,\n\tsignal,\n\ttype WritableSignal,\n} from '@angular/core';\n\n/**\n * Returns a reactive signal that tracks the size of a DOM element.\n *\n * This function uses a shared {@link ResizeObserver} internally to monitor multiple elements efficiently.\n * The returned signal updates whenever the element's width or height changes. It is fully SSR-safe.\n *\n * @param options Optional {@link ElementSizeOptions} configuration object.\n * @param options.elementRef The {@link ElementRef} of the element to observe. Defaults to the {@link ElementRef} injected in the current context.\n * @param options.injector Optional custom {@link Injector} to run the function in. Defaults to the current injection context.\n *\n * @returns A readonly {@link Signal} containing `{ width, height }` of the element, or `undefined` if the element has not yet been measured or on the server.\n *\n * Based on https://github.com/radix-ui/primitives/blob/main/packages/react/use-size/src/use-size.tsx\n */\nexport function injectElementSize(\n\toptions: ElementSizeOptions = {},\n): Signal<{ width: number; height: number } | undefined> {\n\treturn runInInjectionContext(options.injector ?? inject(Injector), () => {\n\t\tconst elementRef = options.elementRef ?? inject(ElementRef);\n\t\tconst platformId = inject(PLATFORM_ID);\n\t\tconst destroyRef = inject(DestroyRef);\n\n\t\tconst element = elementRef.nativeElement;\n\t\tconst size = signal<{ width: number; height: number } | undefined>(undefined);\n\n\t\tif (isPlatformServer(platformId)) {\n\t\t\treturn size;\n\t\t}\n\n\t\tafterNextRender({\n\t\t\tread: () => {\n\t\t\t\t// Initial read\n\t\t\t\tconst rect = element.getBoundingClientRect();\n\t\t\t\tsize.set({\n\t\t\t\t\twidth: rect.width || element.offsetWidth,\n\t\t\t\t\theight: rect.height || element.offsetHeight,\n\t\t\t\t});\n\n\t\t\t\t// Register element in shared observer\n\t\t\t\tobserverMap.set(element, { element, size });\n\t\t\t\tgetSharedObserver().observe(element, { box: 'border-box' });\n\n\t\t\t\tdestroyRef.onDestroy(() => {\n\t\t\t\t\tgetSharedObserver().unobserve(element);\n\t\t\t\t\tobserverMap.delete(element);\n\n\t\t\t\t\t// Disconnect global observer if no elements left\n\t\t\t\t\tif (observerMap.size === 0 && sharedObserver) {\n\t\t\t\t\t\tsharedObserver.disconnect();\n\t\t\t\t\t\tsharedObserver = undefined;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t});\n\n\t\treturn size.asReadonly();\n\t});\n}\n\nconst observerMap = new Map<HTMLElement, SizeEntry>();\nlet sharedObserver: ResizeObserver | undefined;\n\nfunction getSharedObserver() {\n\tif (!sharedObserver) {\n\t\tsharedObserver = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tconst el = entry.target as HTMLElement;\n\t\t\t\tconst entryData = observerMap.get(el);\n\t\t\t\tif (!entryData) continue;\n\n\t\t\t\tlet width: number;\n\t\t\t\tlet height: number;\n\n\t\t\t\tif ('borderBoxSize' in entry) {\n\t\t\t\t\t// Iron out differences between browsers\n\t\t\t\t\tconst borderSize = Array.isArray(entry.borderBoxSize) ? entry.borderBoxSize[0] : entry.borderBoxSize;\n\t\t\t\t\twidth = borderSize.inlineSize;\n\t\t\t\t\theight = borderSize.blockSize;\n\t\t\t\t} else {\n\t\t\t\t\twidth = el.offsetWidth;\n\t\t\t\t\theight = el.offsetHeight;\n\t\t\t\t}\n\n\t\t\t\tentryData.size.set({ width, height });\n\t\t\t}\n\t\t});\n\t}\n\n\treturn sharedObserver;\n}\n\n/**\n * Options to configure `injectElementSize`.\n */\ninterface ElementSizeOptions {\n\t/** The ElementRef of the element to observe. Defaults to injected ElementRef in the current context. */\n\telementRef?: ElementRef<HTMLElement>;\n\t/** Optional Injector to run the function in. Defaults to the current injection context. */\n\tinjector?: Injector;\n}\n\n/**\n * Internal type used to track each observed element in the shared ResizeObserver.\n */\ninterface SizeEntry {\n\t/** The HTML element being observed. */\n\telement: HTMLElement;\n\t/** Writable signal storing the element's current width and height. */\n\tsize: WritableSignal<{ width: number; height: number } | undefined>;\n}\n","import type { ConnectedPosition } from '@angular/cdk/overlay';\nimport { InjectionToken } from '@angular/core';\n\nexport type MenuAlign = 'start' | 'center' | 'end';\nexport type MenuSide = 'top' | 'bottom' | 'left' | 'right';\n\nconst OPPOSITE_SIDE: Record<string, MenuSide> = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' };\n\n/**\n * Lets a menu trigger expose its configured `side` to the portaled content. CDK gives the content a\n * child injector whose parent is the trigger's injector, so the content can resolve this token to\n * learn which axis to read off the transform-origin.\n */\nexport interface MenuSideProvider {\n\treadonly side: () => MenuSide;\n}\n\nexport const MENU_SIDE = new InjectionToken<MenuSideProvider>('SpartanMenuSide');\n\n// derive data-side from the transform-origin CDK sets on the content. the anchored corner faces the\n// trigger, so the side is its opposite. the configured `side` tells us which axis carries the anchor\n// (top/bottom -> vertical token, left/right -> horizontal), so a CDK flip is read off the right axis.\n// CDK's origin is rtl-aware, so the derived side is too. falls back to the configured side when the\n// transform-origin is missing or centered (no flip information to apply).\nexport const deriveMenuSideFromTransformOrigin = (transformOrigin: string, side: MenuSide): MenuSide => {\n\tconst [x, y] = transformOrigin.trim().split(/\\s+/);\n\tconst anchor = side === 'top' || side === 'bottom' ? y : x;\n\treturn OPPOSITE_SIDE[anchor] ?? side;\n};\n\nexport const createMenuPosition = (align: MenuAlign, side: MenuSide): ConnectedPosition[] => {\n\tconst verticalAlign = align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center';\n\n\tconst createPositions = (\n\t\toriginX: 'start' | 'center' | 'end',\n\t\toriginY: 'top' | 'center' | 'bottom',\n\t\toverlayX: 'start' | 'center' | 'end',\n\t\toverlayY: 'top' | 'center' | 'bottom',\n\t): ConnectedPosition[] => [\n\t\t{ originX, originY, overlayX, overlayY },\n\t\t{ originX: overlayX, originY: overlayY, overlayX: originX, overlayY: originY },\n\t];\n\n\tswitch (side) {\n\t\tcase 'top':\n\t\t\treturn createPositions(align, 'top', align, 'bottom');\n\t\tcase 'bottom':\n\t\t\treturn createPositions(align, 'bottom', align, 'top');\n\t\tcase 'left':\n\t\t\treturn createPositions('start', verticalAlign, 'end', verticalAlign);\n\t\tcase 'right':\n\t\t\treturn createPositions('end', verticalAlign, 'start', verticalAlign);\n\t}\n};\n","export function stringifyAsLabel(item: any, itemToStringLabel?: (item: any) => string) {\n\tif (itemToStringLabel && item !== null && item !== undefined) {\n\t\treturn itemToStringLabel(item) ?? '';\n\t}\n\tif (item && typeof item === 'object') {\n\t\tif ('label' in item && item.label !== null && item.label !== undefined) {\n\t\t\treturn String(item.label);\n\t\t}\n\t\tif ('value' in item && item.value !== null && item.value !== undefined) {\n\t\t\treturn String(item.value);\n\t\t}\n\t}\n\treturn serializeValue(item);\n}\n\nexport function serializeValue(value: unknown): string {\n\tif (value === null || value === undefined) {\n\t\treturn '';\n\t}\n\tif (typeof value === 'string') {\n\t\treturn value;\n\t}\n\ttry {\n\t\treturn JSON.stringify(value);\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n","import { DestroyRef, inject, type Signal, signal } from '@angular/core';\n\n/** Skip-delay grouping: once one member opens, siblings skip their delay until the window elapses. */\nexport interface SkipDelay {\n\t/** Whether the next open should still wait for its delay (`true`) or open instantly (`false`). */\n\treadonly isOpenDelayed: Signal<boolean>;\n\t/** Report that a member opened: opens the skip window so siblings skip their delay. */\n\topen(): void;\n\t/** Report that a member closed: re-require the delay once the window elapses. */\n\tclose(): void;\n}\n\n/** Must be called in an injection context; cleans up its pending timer on destroy. */\nexport function injectSkipDelay(skipDelayDuration: () => number): SkipDelay {\n\tconst isOpenDelayed = signal(true);\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\n\tinject(DestroyRef).onDestroy(() => clearTimeout(timer));\n\n\treturn {\n\t\tisOpenDelayed: isOpenDelayed.asReadonly(),\n\t\topen(): void {\n\t\t\tclearTimeout(timer);\n\t\t\tif (skipDelayDuration() > 0) isOpenDelayed.set(false);\n\t\t},\n\t\tclose(): void {\n\t\t\tclearTimeout(timer);\n\t\t\tconst duration = skipDelayDuration();\n\t\t\tif (duration > 0) {\n\t\t\t\ttimer = setTimeout(() => isOpenDelayed.set(true), duration);\n\t\t\t}\n\t\t},\n\t};\n}\n","import { createInjectionToken } from './create-injection-token';\n\nexport interface TableClassesSettable {\n\tsetTableClasses: (classes: Partial<{ table: string; headerRow: string; bodyRow: string }>) => void;\n}\n\nexport const [\n\tinjectTableClassesSettable,\n\tprovideTableClassesSettable,\n\tprovideTableClassesSettableExisting,\n\tSET_TABLE_CLASSES_TOKEN,\n] = createInjectionToken<TableClassesSettable>('@spartan-ng SET_TABLE_CLASSES_TOKEN');\n","const MAX_ANIMATION_WAIT_MS = 5_000;\nconst ANIMATION_WAIT_BUFFER_MS = 50;\n\nexport function getActiveElementAnimations(elements: readonly (HTMLElement | null | undefined)[]): Animation[] {\n\treturn elements\n\t\t.filter((element): element is HTMLElement => !!element)\n\t\t.flatMap((element) =>\n\t\t\ttypeof element.getAnimations === 'function'\n\t\t\t\t? element.getAnimations({ subtree: true }).filter((animation) => animation.playState !== 'finished')\n\t\t\t\t: [],\n\t\t);\n}\n\nexport async function waitForAnimations(animations: readonly Animation[]): Promise<void> {\n\tif (!animations.length) return;\n\n\tlet timeout: ReturnType<typeof setTimeout> | undefined;\n\tconst fallbackMs = getFallbackTimeout(animations);\n\n\ttry {\n\t\tawait Promise.race([\n\t\t\tPromise.allSettled(animations.map((animation) => animation.finished)),\n\t\t\tnew Promise<void>((resolve) => {\n\t\t\t\ttimeout = setTimeout(resolve, fallbackMs);\n\t\t\t}),\n\t\t]);\n\t} finally {\n\t\tif (timeout) clearTimeout(timeout);\n\t}\n}\n\n/**\n * Waits for active animations, including subtree animations, within the given element to finish.\n */\nexport async function waitForElementAnimations(element: HTMLElement): Promise<void> {\n\tawait waitForAnimations(getActiveElementAnimations([element]));\n}\n\nfunction getFallbackTimeout(animations: readonly Animation[]): number {\n\tconst longestAnimation = animations.reduce((longest, animation) => {\n\t\tconst endTime = animation.effect?.getComputedTiming().endTime;\n\t\treturn typeof endTime === 'number' && Number.isFinite(endTime) ? Math.max(longest, endTime) : longest;\n\t}, 0);\n\n\tif (!longestAnimation) return MAX_ANIMATION_WAIT_MS;\n\treturn Math.min(longestAnimation + ANIMATION_WAIT_BUFFER_MS, MAX_ANIMATION_WAIT_MS);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -18,7 +18,6 @@ const defaultOptions = {
18
18
  attachTo: null,
19
19
  autoFocus: 'first-tabbable',
20
20
  backdropClass: '',
21
- closeOnBackdropClick: true,
22
21
  closeOnOutsidePointerEvents: false,
23
22
  disableClose: false,
24
23
  hasBackdrop: true,
@@ -96,8 +95,6 @@ class BrnDialogRef {
96
95
  const options = this.initialOptions;
97
96
  if (!this.open || options.disableClose)
98
97
  return false;
99
- if (reason === 'backdrop' && !options.closeOnBackdropClick)
100
- return false;
101
98
  if (reason === 'outside' && !options.closeOnOutsidePointerEvents)
102
99
  return false;
103
100
  this.close();
@@ -140,6 +137,12 @@ class BrnDialogRef {
140
137
  if (generation !== this._closeGeneration || this._phase() !== 'closing')
141
138
  return;
142
139
  const exitAnimations = this._getActiveAnimations().filter((animation) => !animationsBeforeClose.has(animation));
140
+ // Pin each exit animation to its final frame. tw-animate-css uses `animation-fill-mode: none`,
141
+ // so a finished exit reverts the element to its visible state in the gap before we dispose it -
142
+ // that one-frame snap-back is the flicker. updateTiming pins only the animations we await.
143
+ for (const animation of exitAnimations) {
144
+ animation.effect?.updateTiming({ fill: 'forwards' });
145
+ }
143
146
  await waitForAnimations(exitAnimations);
144
147
  if (generation === this._closeGeneration && this._phase() === 'closing') {
145
148
  this._phase.set('closed');
@@ -307,7 +310,6 @@ class BrnDialog {
307
310
  scrollStrategy = input(this._defaultOptions.scrollStrategy, ...(ngDevMode ? [{ debugName: "scrollStrategy" }] : /* istanbul ignore next */ []));
308
311
  restoreFocus = input(this._defaultOptions.restoreFocus, ...(ngDevMode ? [{ debugName: "restoreFocus" }] : /* istanbul ignore next */ []));
309
312
  closeOnOutsidePointerEvents = input(this._defaultOptions.closeOnOutsidePointerEvents, { ...(ngDevMode ? { debugName: "closeOnOutsidePointerEvents" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
310
- closeOnBackdropClick = input(this._defaultOptions.closeOnBackdropClick, { ...(ngDevMode ? { debugName: "closeOnBackdropClick" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
311
313
  attachTo = input(this._defaultOptions.attachTo, ...(ngDevMode ? [{ debugName: "attachTo" }] : /* istanbul ignore next */ []));
312
314
  attachPositions = input(this._defaultOptions.attachPositions, ...(ngDevMode ? [{ debugName: "attachPositions" }] : /* istanbul ignore next */ []));
313
315
  autoFocus = input(this._defaultOptions.autoFocus, ...(ngDevMode ? [{ debugName: "autoFocus" }] : /* istanbul ignore next */ []));
@@ -326,7 +328,6 @@ class BrnDialog {
326
328
  scrollStrategy: this.getScrollStrategy(),
327
329
  restoreFocus: this.restoreFocus(),
328
330
  closeOnOutsidePointerEvents: this.closeOnOutsidePointerEvents(),
329
- closeOnBackdropClick: this.closeOnBackdropClick(),
330
331
  attachTo: this.getAttachTo(),
331
332
  attachPositions: this.attachPositions(),
332
333
  autoFocus: this.autoFocus(),
@@ -432,7 +433,7 @@ class BrnDialog {
432
433
  }, { injector: this._injector });
433
434
  }
434
435
  /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: BrnDialog, deps: [], target: i0.ɵɵFactoryTarget.Directive });
435
- /** @nocollapse */ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.16", type: BrnDialog, isStandalone: true, selector: "[brnDialog],brn-dialog", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, hasBackdrop: { classPropertyName: "hasBackdrop", publicName: "hasBackdrop", isSignal: true, isRequired: false, transformFunction: null }, positionStrategy: { classPropertyName: "positionStrategy", publicName: "positionStrategy", isSignal: true, isRequired: false, transformFunction: null }, scrollStrategy: { classPropertyName: "scrollStrategy", publicName: "scrollStrategy", isSignal: true, isRequired: false, transformFunction: null }, restoreFocus: { classPropertyName: "restoreFocus", publicName: "restoreFocus", isSignal: true, isRequired: false, transformFunction: null }, closeOnOutsidePointerEvents: { classPropertyName: "closeOnOutsidePointerEvents", publicName: "closeOnOutsidePointerEvents", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdropClick: { classPropertyName: "closeOnBackdropClick", publicName: "closeOnBackdropClick", isSignal: true, isRequired: false, transformFunction: null }, attachTo: { classPropertyName: "attachTo", publicName: "attachTo", isSignal: true, isRequired: false, transformFunction: null }, attachPositions: { classPropertyName: "attachPositions", publicName: "attachPositions", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, disableClose: { classPropertyName: "disableClose", publicName: "disableClose", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaModal: { classPropertyName: "ariaModal", publicName: "aria-modal", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", stateChanged: "stateChanged" }, exportAs: ["brnDialog"], ngImport: i0 });
436
+ /** @nocollapse */ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.16", type: BrnDialog, isStandalone: true, selector: "[brnDialog],brn-dialog", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, hasBackdrop: { classPropertyName: "hasBackdrop", publicName: "hasBackdrop", isSignal: true, isRequired: false, transformFunction: null }, positionStrategy: { classPropertyName: "positionStrategy", publicName: "positionStrategy", isSignal: true, isRequired: false, transformFunction: null }, scrollStrategy: { classPropertyName: "scrollStrategy", publicName: "scrollStrategy", isSignal: true, isRequired: false, transformFunction: null }, restoreFocus: { classPropertyName: "restoreFocus", publicName: "restoreFocus", isSignal: true, isRequired: false, transformFunction: null }, closeOnOutsidePointerEvents: { classPropertyName: "closeOnOutsidePointerEvents", publicName: "closeOnOutsidePointerEvents", isSignal: true, isRequired: false, transformFunction: null }, attachTo: { classPropertyName: "attachTo", publicName: "attachTo", isSignal: true, isRequired: false, transformFunction: null }, attachPositions: { classPropertyName: "attachPositions", publicName: "attachPositions", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, disableClose: { classPropertyName: "disableClose", publicName: "disableClose", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaModal: { classPropertyName: "ariaModal", publicName: "aria-modal", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", stateChanged: "stateChanged" }, exportAs: ["brnDialog"], ngImport: i0 });
436
437
  }
437
438
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: BrnDialog, decorators: [{
438
439
  type: Directive,
@@ -440,7 +441,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
440
441
  selector: '[brnDialog],brn-dialog',
441
442
  exportAs: 'brnDialog',
442
443
  }]
443
- }], ctorParameters: () => [], propDecorators: { closed: [{ type: i0.Output, args: ["closed"] }], stateChanged: [{ type: i0.Output, args: ["stateChanged"] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], hasBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasBackdrop", required: false }] }], positionStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "positionStrategy", required: false }] }], scrollStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollStrategy", required: false }] }], restoreFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "restoreFocus", required: false }] }], closeOnOutsidePointerEvents: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnOutsidePointerEvents", required: false }] }], closeOnBackdropClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnBackdropClick", required: false }] }], attachTo: [{ type: i0.Input, args: [{ isSignal: true, alias: "attachTo", required: false }] }], attachPositions: [{ type: i0.Input, args: [{ isSignal: true, alias: "attachPositions", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], disableClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableClose", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-describedby", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaModal: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-modal", required: false }] }] } });
444
+ }], ctorParameters: () => [], propDecorators: { closed: [{ type: i0.Output, args: ["closed"] }], stateChanged: [{ type: i0.Output, args: ["stateChanged"] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], hasBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasBackdrop", required: false }] }], positionStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "positionStrategy", required: false }] }], scrollStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollStrategy", required: false }] }], restoreFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "restoreFocus", required: false }] }], closeOnOutsidePointerEvents: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnOutsidePointerEvents", required: false }] }], attachTo: [{ type: i0.Input, args: [{ isSignal: true, alias: "attachTo", required: false }] }], attachPositions: [{ type: i0.Input, args: [{ isSignal: true, alias: "attachPositions", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], disableClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableClose", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-describedby", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaModal: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-modal", required: false }] }] } });
444
445
 
445
446
  class BrnDialogClose {
446
447
  _brnDialogRef = inject(BrnDialogRef);