@ynmstudio/utils
Version:
YNM Utilities for Angular
141 lines (135 loc) • 7.63 kB
JavaScript
import * as i0 from '@angular/core';
import { input, Component, InjectionToken, Optional, SkipSelf, inject, ViewContainerRef, Injector, Renderer2, EnvironmentInjector, numberAttribute, computed, effect, createComponent, Directive } from '@angular/core';
class DynamicHeadingComponent {
constructor() {
this.class = input('');
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: DynamicHeadingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.13", type: DynamicHeadingComponent, isStandalone: true, selector: "[dynamicHeadingWrapper]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "class()" } }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host.debug ::ng-deep>*{position:relative}:host.debug ::ng-deep>*:after{position:absolute;background-color:#ffb6c1;color:#fff;font-size:12px;padding:.25em;line-height:1.1;border-radius:2px;content:\"H\" attr(data-level) / \"Heading \" attr(data-level);top:0;right:0;transform:translateY(-50%)}:host.debug:hover ::ng-deep>*:after{background-color:red}\n"] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: DynamicHeadingComponent, decorators: [{
type: Component,
args: [{ selector: '[dynamicHeadingWrapper]', template: '<ng-content></ng-content>', host: {
'[class]': 'class()',
}, styles: [":host.debug ::ng-deep>*{position:relative}:host.debug ::ng-deep>*:after{position:absolute;background-color:#ffb6c1;color:#fff;font-size:12px;padding:.25em;line-height:1.1;border-radius:2px;content:\"H\" attr(data-level) / \"Heading \" attr(data-level);top:0;right:0;transform:translateY(-50%)}:host.debug:hover ::ng-deep>*:after{background-color:red}\n"] }]
}] });
/**
* Injection token to control the base heading level within components.
*
* This provider allows setting or resetting the heading level hierarchy within specific components.
* This is useful when you want to start a new heading hierarchy from level 1, regardless of parent levels.
*
* Common use cases include:
* - Reset to h1 at the start of a new <article> element to maintain proper document outline
* - Start fresh heading hierarchy in <aside> elements or sidebars
* - Modal dialogs or overlays that should have their own heading structure
* - Independent widgets or components that can be placed anywhere but need consistent heading levels
* - Blog post or article comments sections that should start their own hierarchy
*
* @example
* ```typescript
* @Component({
* providers: [
* { provide: DYNAMIC_HEADING_LEVEL, useValue: 1 } // Reset to h1
* ]
* })
* ```
*/
const DYNAMIC_HEADING_LEVEL = new InjectionToken('DYNAMIC_HEADING_LEVEL', {
factory: () => 1,
providedIn: 'root',
});
/**
* Injection token to enable debug mode for dynamic headings.
*
* When set to true, a pseudo element will be rendered next to each heading element
* showing its current heading level (e.g. "H2/Heading 2"). This provides visual feedback
* about the computed heading levels during development.
*
* @default false
*/
const DYNAMIC_HEADING_DEBUG = new InjectionToken('DYNAMIC_HEADING_DEBUG', {
factory: () => false,
providedIn: 'root',
});
/**
* Factory function to increase the heading level relative to parent headings.
*
* This can be used in two ways:
* 1. As a provider to automatically increment heading levels by X relative to parent headings
* (e.g. h1 -> h2 -> h3)
* 2. Alternatively, the level/offset inputs can be used directly on the dynamicHeading directive
* to explicitly set the heading level, overriding the automatic increments
*
* @param offset Number of levels to increment from the parent heading level (defaults to 1)
* @returns Provider configuration for DYNAMIC_HEADING_LEVEL
*/
function increaseDynamicHeadingLevel() {
return {
provide: DYNAMIC_HEADING_LEVEL,
useFactory: (parentLevel) => {
// If parentLevel is null or undefined, start from 2
return (parentLevel ?? 1) + 1;
},
deps: [[new Optional(), new SkipSelf(), DYNAMIC_HEADING_LEVEL]],
};
}
class DynamicHeadingDirective {
#viewContainerRef;
#injector;
#renderer;
#environment;
#currentHeadingLevel;
constructor() {
this.#viewContainerRef = inject(ViewContainerRef);
this.#injector = inject(Injector);
this.#renderer = inject(Renderer2);
this.#environment = inject(EnvironmentInjector);
this.#currentHeadingLevel = inject(DYNAMIC_HEADING_LEVEL);
this.debug = inject(DYNAMIC_HEADING_DEBUG);
this.dynamicHeadingClass = input('');
this._level = input(this.#currentHeadingLevel, {
alias: 'level',
transform: (value) => numberAttribute(value) ?? 1
});
this.offset = input(0, {
transform: (value) => numberAttribute(value) ?? 0
});
this.level = computed(() => Math.max(1, Math.min(6, this._level() + this.offset())));
effect(() => {
this.#viewContainerRef?.clear();
const hostElement = this.#renderer.createElement(`h${this.level()}`);
const heading = createComponent(DynamicHeadingComponent, {
hostElement,
environmentInjector: this.#environment,
elementInjector: this.#injector,
projectableNodes: [
[this.#viewContainerRef.element.nativeElement]
],
});
heading.setInput('class', `${this.dynamicHeadingClass()} ${this.debug ? 'debug' : ''}`);
this.#viewContainerRef.insert(heading.hostView);
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: DynamicHeadingDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.13", type: DynamicHeadingDirective, isStandalone: true, selector: "[dynamicHeading]", inputs: { dynamicHeadingClass: { classPropertyName: "dynamicHeadingClass", publicName: "dynamicHeadingClass", isSignal: true, isRequired: false, transformFunction: null }, _level: { classPropertyName: "_level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-level": "level()" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: DynamicHeadingDirective, decorators: [{
type: Directive,
args: [{
selector: '[dynamicHeading]',
standalone: true,
host: {
'[attr.data-level]': 'level()',
},
}]
}], ctorParameters: () => [] });
/*
* Public API Surface of draw-blurhash
*/
// export * from './dynamic-heading.component';
/**
* Generated bundle index. Do not edit.
*/
export { DYNAMIC_HEADING_DEBUG, DYNAMIC_HEADING_LEVEL, DynamicHeadingDirective, increaseDynamicHeadingLevel };
//# sourceMappingURL=ynmstudio-utils-dynamic-heading.mjs.map