From ddf7d666656c9a63d4635d29139844e4460947b5 Mon Sep 17 00:00:00 2001 From: Dmitry Shovchko Date: Fri, 30 Aug 2024 16:33:20 +0300 Subject: [PATCH 1/4] style(esl-anchornav): rename props --- .../esl-anchornav/core/esl-anchornav-sticked.ts | 4 ++-- src/modules/esl-anchornav/core/esl-anchornav.ts | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/modules/esl-anchornav/core/esl-anchornav-sticked.ts b/src/modules/esl-anchornav/core/esl-anchornav-sticked.ts index 37cbef9e9..ec10cba15 100644 --- a/src/modules/esl-anchornav/core/esl-anchornav-sticked.ts +++ b/src/modules/esl-anchornav/core/esl-anchornav-sticked.ts @@ -29,7 +29,7 @@ export class ESLAnchornavSticked extends ESLMixinElement { public set sticked(value: boolean) { if (this._sticked === value) return; this._sticked = value; - this.$$attr('sticked', value); + this.$$cls(`${ESLAnchornavSticked.is}-active`, value); this._onStateChange(); } @@ -57,7 +57,7 @@ export class ESLAnchornavSticked extends ESLMixinElement { } @listen({event: 'resize', target: (that: ESLAnchornavSticked) => ESLResizeObserverTarget.for(that.$host)}) - protected _onResize({borderBoxSize}: ESLElementResizeEvent): void { + protected _onResize(e: ESLElementResizeEvent): void { this._onStateChange(); } } diff --git a/src/modules/esl-anchornav/core/esl-anchornav.ts b/src/modules/esl-anchornav/core/esl-anchornav.ts index 15c4c93ea..c71d20378 100644 --- a/src/modules/esl-anchornav/core/esl-anchornav.ts +++ b/src/modules/esl-anchornav/core/esl-anchornav.ts @@ -45,6 +45,7 @@ export class ESLAnchornav extends ESLBaseElement { @prop('esl:anchornav:activechanged') public ACTIVECHANGED_EVENT: string; @prop('esl:anchornav:updated') public UPDATED_EVENT: string; @prop('[esl-anchor]') protected ANCHOR_SELECTOR: string; + @prop([0, 0.01, 0.99, 1]) protected INTERSECTION_THRESHOLD: number[]; /** Item renderer which is used to build inner markup */ @attr({defaultValue: 'default', name: 'renderer'}) public rendererName: string; @@ -99,13 +100,13 @@ export class ESLAnchornav extends ESLBaseElement { return getViewportForEl(this); } - /** Data for prepend anchor */ - protected get prependData(): ESLAnchorData[] { + /** Permanent anchors to prepend to the list */ + protected get anchorsToPrepend(): ESLAnchorData[] { return []; } - /** Data for append anchor */ - protected get appendData(): ESLAnchorData[] { + /** Permanent anchors to append to the list */ + protected get anchorsToAppend(): ESLAnchorData[] { return []; } @@ -197,8 +198,8 @@ export class ESLAnchornav extends ESLBaseElement { }) protected _onAnchornavRequest(): void { this._anchors = [...document.querySelectorAll(this.ANCHOR_SELECTOR)].map(this.getDataFrom); - this._anchors.unshift(...this.prependData); - this._anchors.push(...this.appendData); + this._anchors.unshift(...this.anchorsToPrepend); + this._anchors.push(...this.anchorsToAppend); this.update(); } @@ -206,7 +207,7 @@ export class ESLAnchornav extends ESLBaseElement { event: 'intersects', target: (that: ESLAnchornav) => ESLIntersectionTarget.for(that.$anchors, { root: that.$viewport, - threshold: [0, 0.01, 0.99, 1], + threshold: that.INTERSECTION_THRESHOLD, rootMargin: `-${that.offset + 1}px 0px 0px 0px` }) }) From 19ce976f9f4d412af58bcd7cec1a427fbdc5cec0 Mon Sep 17 00:00:00 2001 From: Dmitry Shovchko Date: Fri, 30 Aug 2024 16:33:57 +0300 Subject: [PATCH 2/4] docs(esl-anchornav): update README --- src/modules/esl-anchornav/README.md | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/modules/esl-anchornav/README.md b/src/modules/esl-anchornav/README.md index 3936a6474..32a47aa80 100644 --- a/src/modules/esl-anchornav/README.md +++ b/src/modules/esl-anchornav/README.md @@ -9,3 +9,47 @@ Authors: *Dmytro Shovchko*. The ESL Anchornav component allows users to quickly jump to specific page content via predefined anchors. The list of anchors is collected from the page dynamically, so any page updates will be processed and the component updates the navigation list. + +### How it works + +The component collects anchors on the page, builds a list of anchors using the user-defined renderer function, and appends it to the inner items container element (it will be an element with `esl-anchors-items` attribute). After that, the component observes the position of the collected anchors to detect currently active anchor and marks it with active class marker. + +For example, markup may be the following: +```html +Anchors: +``` +If for some reason you do not add an element with this attribute to the component content, it will not be a mistake. A div with the `esl-anchors-items` attribute will be created and added to the component content in this case. + +You can assign anchors to any element on the page. To do this, you must give this element the `esl-anchor` attribute. Another mandatory requirement for an element is that it must contain two attributes `id` and `title` (this is the text to be displayed in the list). + +### Items renderer + +For all collected anchors it is used renderer function which builds the inner content of the anchors list. Here is a default renderer: +```ts +ESLAnchornav.setRenderer((data: ESLAnchorData, index: number, anchornav: ESLAnchornav) => `${data.title}`); +``` +You can define your own renderer. You can define several renderers with different names and use them on different components. + +### ESLAnchornav + +#### Public API +- `setRenderer` - a static method to set item renderer +- `getRenderer` - a static method to get item renderer with specified name +- `active` (ESLAnchorData) - active anchor data +- `offset` (number) - anchornav top offset, used when detects active anchors (0 by default) +- `update` - updates component + +#### Attributes | Properties: + +- `position` - popup position relative to the trigger (currently supported: 'top', 'bottom', 'left', 'right' ) ('top' by default) +- `renderer` - item renderer which is used to build inner markup +- `active-class` - CSS classes to set on active item (and remove when item inactive) + +#### Events + + - `esl:anchornav:activechanged` - event to dispatch on `ESLAnchornav` when active item changed + - `esl:anchornav:updated` - event to dispatch on `ESLAnchornav` updated state + +### ESLAnchornavSticked + +To implement the sticky behavior of a component, you can use the `ESLAnchornavSticked` mixin. Register the mixin and add the `esl-anchornav-sticked` attribute to the anchor element container. From b9d2cacf50de42f8228875a42e2814f57bdc1e31 Mon Sep 17 00:00:00 2001 From: Dmitry Shovchko Date: Fri, 30 Aug 2024 16:36:05 +0300 Subject: [PATCH 3/4] style(esl-anchornav): create jsx tag shape --- .../esl-anchornav/core/esl-anchornav.shape.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/modules/esl-anchornav/core/esl-anchornav.shape.ts diff --git a/src/modules/esl-anchornav/core/esl-anchornav.shape.ts b/src/modules/esl-anchornav/core/esl-anchornav.shape.ts new file mode 100644 index 000000000..6bfabf69c --- /dev/null +++ b/src/modules/esl-anchornav/core/esl-anchornav.shape.ts @@ -0,0 +1,25 @@ +import type {ESLBaseElementShape} from '../../esl-base-element/core/esl-base-element.shape'; +import type {ESLAnchornav} from './esl-anchornav'; + +/** + * Tag declaration interface of {@link ESLAnchornav} element + * Used for TSX declaration + */ +export interface ESLAnchornavTagShape extends ESLBaseElementShape { + /** Item renderer which is used to build inner markup */ + renderer?: string; + /** CSS classes to set on active item */ + 'active-class'?: string; + + /** Allowed children */ + children?: any; +} + +declare global { + namespace JSX { + export interface IntrinsicElements { + /** {@link ESLAnchornav} custom tag */ + 'esl-anchornav': ESLAnchornavTagShape; + } + } +} From 851290a7e1cd261e73946742bf2ff95fe64021bc Mon Sep 17 00:00:00 2001 From: Dmitry Shovchko Date: Fri, 30 Aug 2024 16:39:41 +0300 Subject: [PATCH 4/4] docs(esl-anchornav): update README --- src/modules/esl-anchornav/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/esl-anchornav/README.md b/src/modules/esl-anchornav/README.md index 32a47aa80..46dac4cb0 100644 --- a/src/modules/esl-anchornav/README.md +++ b/src/modules/esl-anchornav/README.md @@ -41,7 +41,6 @@ You can define your own renderer. You can define several renderers with differen #### Attributes | Properties: -- `position` - popup position relative to the trigger (currently supported: 'top', 'bottom', 'left', 'right' ) ('top' by default) - `renderer` - item renderer which is used to build inner markup - `active-class` - CSS classes to set on active item (and remove when item inactive)