@cntrl-site/sdk-nextjs 1.9.77 → 1.9.79
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.
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/modules.xml +8 -0
- package/.idea/sdk-nextjs.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/LICENSE +21 -21
- package/README.md +4 -4
- package/TODO.md +1 -1
- package/eslint.config.mjs +35 -35
- package/jest.config.js +6 -6
- package/lib/common/useItemFXData.js +5 -5
- package/lib/components/Article.js +5 -5
- package/lib/components/LayoutStyle.js +4 -4
- package/lib/components/Section/Section.js +27 -27
- package/lib/components/StructuredBlockItem/StructuredBlockItem.js +13 -13
- package/lib/components/StructuredBlockItem/StructuredComponent/StructuredComponent.js +12 -12
- package/lib/components/StructuredContent/StructuredContent.js +11 -11
- package/lib/components/items/CodeEmbedItem/CodeEmbedItem.js +36 -36
- package/lib/components/items/ComponentItem/ComponentItem.js +13 -13
- package/lib/components/items/CompoundItem/CompoundChild.js +20 -20
- package/lib/components/items/CompoundItem/CompoundItem.js +14 -14
- package/lib/components/items/CustomItem/CustomItem.js +9 -9
- package/lib/components/items/EmbedVideoItem/VimeoEmbed.js +24 -24
- package/lib/components/items/EmbedVideoItem/YoutubeEmbed.js +27 -27
- package/lib/components/items/FileItem/ImageItem.js +40 -40
- package/lib/components/items/FileItem/VideoItem.js +64 -64
- package/lib/components/items/GroupItem/GroupItem.js +14 -14
- package/lib/components/items/Item.js +30 -30
- package/lib/components/items/RectangleItem/RectangleItem.js +27 -27
- package/lib/components/items/RichTextItem/RichTextItem.js +22 -22
- package/lib/utils/RichTextConverter/RichTextConverter.js +21 -21
- package/package.json +62 -62
- package/src/ItemGeometry/CSSPropertyNameMap.ts +37 -37
- package/src/ItemGeometry/GenericGeometryController.ts +59 -59
- package/src/ItemGeometry/ItemGeometryContext.ts +4 -4
- package/src/ItemGeometry/ItemGeometryController.ts +22 -22
- package/src/ItemGeometry/ItemGeometryService.ts +34 -34
- package/src/ItemGeometry/RichTextGeometryController.ts +166 -166
- package/src/ItemGeometry/useItemGeometry.ts +25 -25
- package/src/common/useCurrentLayout.ts +52 -52
- package/src/common/useExemplary.ts +9 -9
- package/src/common/useItemFXData.ts +63 -63
- package/src/common/useKeyframeValue.ts +85 -85
- package/src/common/useRegisterResize.ts +16 -16
- package/src/components/Article.tsx +69 -69
- package/src/components/ArticleWrapper.tsx +21 -21
- package/src/components/Head.tsx +95 -95
- package/src/components/LayoutStyle.tsx +21 -21
- package/src/components/Page.tsx +47 -47
- package/src/components/ScrollPlaybackVideo.tsx +75 -75
- package/src/components/Section/Section.tsx +162 -162
- package/src/components/Section/SectionImage.tsx +48 -48
- package/src/components/Section/SectionVideo.tsx +144 -144
- package/src/components/Section/useSectionColor.ts +19 -19
- package/src/components/Section/useSectionHeightMap.ts +19 -19
- package/src/components/StructuredBlockItem/StructuredBlockItem.tsx +69 -69
- package/src/components/StructuredBlockItem/StructuredComponent/StructuredComponent.tsx +66 -66
- package/src/components/StructuredContent/StructuredContent.tsx +42 -42
- package/src/components/items/CodeEmbedItem/CodeEmbedItem.tsx +148 -148
- package/src/components/items/CodeEmbedItem/useCodeEmbedItem.ts +36 -36
- package/src/components/items/ComponentItem/ComponentItem.tsx +85 -85
- package/src/components/items/ComponentItem/useComponentItem.ts +35 -35
- package/src/components/items/CompoundItem/CompoundChild.tsx +151 -151
- package/src/components/items/CompoundItem/CompoundItem.tsx +88 -88
- package/src/components/items/CompoundItem/useCompoundItem.ts +21 -21
- package/src/components/items/CustomItem/CustomItem.tsx +50 -50
- package/src/components/items/EmbedVideoItem/VimeoEmbed.tsx +217 -217
- package/src/components/items/EmbedVideoItem/YoutubeEmbed.tsx +201 -201
- package/src/components/items/EmbedVideoItem/useEmbedVideoItem.ts +46 -46
- package/src/components/items/FileItem/ImageItem.tsx +166 -166
- package/src/components/items/FileItem/VideoItem.tsx +287 -287
- package/src/components/items/FileItem/useFileItem.ts +81 -81
- package/src/components/items/GroupItem/GroupItem.tsx +99 -99
- package/src/components/items/GroupItem/useGroupItem.ts +34 -34
- package/src/components/items/Item.tsx +268 -268
- package/src/components/items/LinkWrapper.tsx +39 -39
- package/src/components/items/RectangleItem/RectangleItem.tsx +177 -177
- package/src/components/items/RectangleItem/useRectangleItem.ts +89 -89
- package/src/components/items/RichTextItem/RichTextItem.tsx +113 -113
- package/src/components/items/RichTextItem/useRichTextItem.ts +12 -12
- package/src/components/items/RichTextWrapper.tsx +15 -15
- package/src/components/items/itemsMap.ts +28 -28
- package/src/components/items/useDraggable.ts +252 -252
- package/src/components/items/useItemAngle.ts +13 -13
- package/src/components/items/useItemArea.ts +35 -35
- package/src/components/items/useItemPointerEvents.ts +23 -23
- package/src/components/items/useItemScale.ts +17 -17
- package/src/components/items/useItemTriggers.ts +15 -15
- package/src/components/items/useRichTextItemValues.ts +66 -66
- package/src/components/items/useSizing.ts +25 -25
- package/src/components/items/useStickyItemTop.ts +21 -21
- package/src/components/useLayoutContext.ts +7 -7
- package/src/index.ts +25 -25
- package/src/interactions/InteractionsRegistry.ts +513 -513
- package/src/interactions/ItemInteractionCtrl.ts +78 -78
- package/src/interactions/getTransition.ts +27 -27
- package/src/interactions/types.ts +36 -36
- package/src/interactions/useItemInteractionCtrl.ts +18 -18
- package/src/provider/ArticleRectContext.ts +4 -4
- package/src/provider/CntrlContext.ts +5 -5
- package/src/provider/CntrlProvider.tsx +11 -11
- package/src/provider/CntrlSdkContext.ts +113 -113
- package/src/provider/CustomItemRegistry.ts +14 -14
- package/src/provider/CustomItemTypes.ts +3 -3
- package/src/provider/CustomSectionRegistry.ts +25 -25
- package/src/provider/InteractionsContext.tsx +73 -73
- package/src/provider/Keyframes.ts +11 -11
- package/src/provider/KeyframesContext.ts +5 -5
- package/src/provider/LayoutContext.ts +3 -3
- package/src/provider/WebGLContextManagerContext.tsx +4 -4
- package/src/provider/defaultContext.ts +8 -8
- package/src/provider/useCntrlContext.ts +8 -8
- package/src/styled-jsx.d.ts +1 -1
- package/src/types/components-utils.d.ts +7 -7
- package/src/utils/Animator/Animator.ts +570 -570
- package/src/utils/ArticleRectManager/ArticleRectObserver.ts +93 -93
- package/src/utils/ArticleRectManager/useArticleRectObserver.ts +17 -17
- package/src/utils/ArticleRectManager/useSectionRegistry.ts +11 -11
- package/src/utils/CSSNumeric.ts +19 -19
- package/src/utils/EventEmitter.ts +41 -41
- package/src/utils/RichTextConverter/RichTextConverter.tsx +342 -342
- package/src/utils/ScaleAnchorMap.ts +13 -13
- package/src/utils/StickyManager/StickyManager.ts +23 -23
- package/src/utils/Youtube/YouTubeIframeApiLoader.ts +58 -58
- package/src/utils/Youtube/YoutubeIframeApi.ts +101 -101
- package/src/utils/Youtube/useYouTubeIframeApi.ts +12 -12
- package/src/utils/areFillsVisible/areFillsVisible.test.ts +63 -63
- package/src/utils/areFillsVisible/areFillsVisible.ts +37 -37
- package/src/utils/binSearchInsertAt.ts +33 -33
- package/src/utils/castObject.ts +10 -10
- package/src/utils/checkOverflowClipSupport.ts +13 -13
- package/src/utils/domDfs.ts +11 -11
- package/src/utils/effects/useImageFx.ts +154 -154
- package/src/utils/effects/useVideoFx.ts +156 -156
- package/src/utils/evaluateComponentBundle.ts +83 -83
- package/src/utils/getAnchoredItemTop.ts +12 -12
- package/src/utils/getCompoundBoundaryStyles.ts +60 -60
- package/src/utils/getFill.ts +46 -46
- package/src/utils/getFontFamilyValue.ts +3 -3
- package/src/utils/getInvertedRanges.ts +43 -43
- package/src/utils/getItemTopStyle.ts +39 -39
- package/src/utils/getStyleFromItemStateAndParams.ts +8 -8
- package/src/utils/getValidYoutubeUrl.ts +29 -29
- package/src/utils/isItemType.ts +5 -5
- package/src/utils/rangeMap.ts +13 -13
- package/src/utils/useElementRect.ts +23 -23
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
import { EventEmitter } from '../EventEmitter';
|
|
2
|
-
import ResizeObserver from 'resize-observer-polyfill';
|
|
3
|
-
|
|
4
|
-
interface EventMap {
|
|
5
|
-
'scroll': undefined;
|
|
6
|
-
'resize': DOMRect;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export class ArticleRectObserver extends EventEmitter<EventMap> {
|
|
10
|
-
private resizeObserver: ResizeObserver;
|
|
11
|
-
private articleWidth: number = 0;
|
|
12
|
-
private registry: Map<string, HTMLElement> = new Map();
|
|
13
|
-
private scrollPos: number = window.scrollY;
|
|
14
|
-
private animationFrame: number = NaN;
|
|
15
|
-
private parent: HTMLElement | undefined = undefined;
|
|
16
|
-
private sectionsScrollMap: Map<string, number> = new Map();
|
|
17
|
-
|
|
18
|
-
constructor() {
|
|
19
|
-
super();
|
|
20
|
-
this.resizeObserver = new ResizeObserver(this.handleResize.bind(this));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
get scroll(): number {
|
|
24
|
-
return this.scrollPos;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
getSectionScroll(sectionId: string): number {
|
|
28
|
-
const sectionTop = this.sectionsScrollMap.get(sectionId);
|
|
29
|
-
if (sectionTop === undefined) return 0;
|
|
30
|
-
return -(sectionTop / this.articleWidth - this.scrollPos);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
getSectionTop(sectionId: string): number {
|
|
34
|
-
const sectionTop = this.sectionsScrollMap.get(sectionId);
|
|
35
|
-
return sectionTop ?? 0;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
get width(): number {
|
|
39
|
-
return this.articleWidth;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
private setScroll(scroll: number) {
|
|
43
|
-
this.scrollPos = scroll;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
init(parent: HTMLElement) {
|
|
47
|
-
this.parent = parent;
|
|
48
|
-
const onScroll = () => {
|
|
49
|
-
this.handleScroll(window.scrollY);
|
|
50
|
-
if (!isNaN(this.animationFrame)) return;
|
|
51
|
-
this.animationFrame = window.requestAnimationFrame(() => {
|
|
52
|
-
this.animationFrame = NaN;
|
|
53
|
-
this.emit('scroll', undefined);
|
|
54
|
-
});
|
|
55
|
-
};
|
|
56
|
-
window.addEventListener('scroll', onScroll);
|
|
57
|
-
return () => {
|
|
58
|
-
this.parent = undefined;
|
|
59
|
-
window.removeEventListener('scroll', onScroll);
|
|
60
|
-
if (!isNaN(this.animationFrame)) {
|
|
61
|
-
window.cancelAnimationFrame(this.animationFrame);
|
|
62
|
-
this.animationFrame = NaN;
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
register(el: HTMLElement, sectionId: string) {
|
|
68
|
-
this.registry.set(sectionId, el);
|
|
69
|
-
this.resizeObserver.observe(el);
|
|
70
|
-
return () => {
|
|
71
|
-
this.registry.delete(sectionId);
|
|
72
|
-
this.resizeObserver.unobserve(el);
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
private handleScroll = (scroll: number) => {
|
|
77
|
-
this.setScroll(scroll / this.articleWidth);
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
private handleResize() {
|
|
81
|
-
if (!this.parent) return;
|
|
82
|
-
const parentBoundary = this.parent.getBoundingClientRect();
|
|
83
|
-
this.articleWidth = parentBoundary.width;
|
|
84
|
-
this.setScroll(window.scrollY / this.articleWidth);
|
|
85
|
-
this.emit('resize', parentBoundary);
|
|
86
|
-
for (const sectionId of this.registry.keys()) {
|
|
87
|
-
const el = this.registry.get(sectionId);
|
|
88
|
-
if (!el) continue;
|
|
89
|
-
const rect = el.getBoundingClientRect();
|
|
90
|
-
this.sectionsScrollMap.set(sectionId, rect.top - parentBoundary.top);
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
}
|
|
1
|
+
import { EventEmitter } from '../EventEmitter';
|
|
2
|
+
import ResizeObserver from 'resize-observer-polyfill';
|
|
3
|
+
|
|
4
|
+
interface EventMap {
|
|
5
|
+
'scroll': undefined;
|
|
6
|
+
'resize': DOMRect;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class ArticleRectObserver extends EventEmitter<EventMap> {
|
|
10
|
+
private resizeObserver: ResizeObserver;
|
|
11
|
+
private articleWidth: number = 0;
|
|
12
|
+
private registry: Map<string, HTMLElement> = new Map();
|
|
13
|
+
private scrollPos: number = window.scrollY;
|
|
14
|
+
private animationFrame: number = NaN;
|
|
15
|
+
private parent: HTMLElement | undefined = undefined;
|
|
16
|
+
private sectionsScrollMap: Map<string, number> = new Map();
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
super();
|
|
20
|
+
this.resizeObserver = new ResizeObserver(this.handleResize.bind(this));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get scroll(): number {
|
|
24
|
+
return this.scrollPos;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getSectionScroll(sectionId: string): number {
|
|
28
|
+
const sectionTop = this.sectionsScrollMap.get(sectionId);
|
|
29
|
+
if (sectionTop === undefined) return 0;
|
|
30
|
+
return -(sectionTop / this.articleWidth - this.scrollPos);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getSectionTop(sectionId: string): number {
|
|
34
|
+
const sectionTop = this.sectionsScrollMap.get(sectionId);
|
|
35
|
+
return sectionTop ?? 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get width(): number {
|
|
39
|
+
return this.articleWidth;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private setScroll(scroll: number) {
|
|
43
|
+
this.scrollPos = scroll;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
init(parent: HTMLElement) {
|
|
47
|
+
this.parent = parent;
|
|
48
|
+
const onScroll = () => {
|
|
49
|
+
this.handleScroll(window.scrollY);
|
|
50
|
+
if (!isNaN(this.animationFrame)) return;
|
|
51
|
+
this.animationFrame = window.requestAnimationFrame(() => {
|
|
52
|
+
this.animationFrame = NaN;
|
|
53
|
+
this.emit('scroll', undefined);
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
window.addEventListener('scroll', onScroll);
|
|
57
|
+
return () => {
|
|
58
|
+
this.parent = undefined;
|
|
59
|
+
window.removeEventListener('scroll', onScroll);
|
|
60
|
+
if (!isNaN(this.animationFrame)) {
|
|
61
|
+
window.cancelAnimationFrame(this.animationFrame);
|
|
62
|
+
this.animationFrame = NaN;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
register(el: HTMLElement, sectionId: string) {
|
|
68
|
+
this.registry.set(sectionId, el);
|
|
69
|
+
this.resizeObserver.observe(el);
|
|
70
|
+
return () => {
|
|
71
|
+
this.registry.delete(sectionId);
|
|
72
|
+
this.resizeObserver.unobserve(el);
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private handleScroll = (scroll: number) => {
|
|
77
|
+
this.setScroll(scroll / this.articleWidth);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
private handleResize() {
|
|
81
|
+
if (!this.parent) return;
|
|
82
|
+
const parentBoundary = this.parent.getBoundingClientRect();
|
|
83
|
+
this.articleWidth = parentBoundary.width;
|
|
84
|
+
this.setScroll(window.scrollY / this.articleWidth);
|
|
85
|
+
this.emit('resize', parentBoundary);
|
|
86
|
+
for (const sectionId of this.registry.keys()) {
|
|
87
|
+
const el = this.registry.get(sectionId);
|
|
88
|
+
if (!el) continue;
|
|
89
|
+
const rect = el.getBoundingClientRect();
|
|
90
|
+
this.sectionsScrollMap.set(sectionId, rect.top - parentBoundary.top);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
import { ArticleRectObserver } from './ArticleRectObserver';
|
|
3
|
-
|
|
4
|
-
export const useArticleRectObserver = (el?: HTMLElement | null) => {
|
|
5
|
-
const [articleRectObserver, setArticleRectObserver] = useState<ArticleRectObserver | null>(null);
|
|
6
|
-
|
|
7
|
-
useEffect(() => {
|
|
8
|
-
setArticleRectObserver(new ArticleRectObserver());
|
|
9
|
-
}, []);
|
|
10
|
-
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
if (!el || !articleRectObserver) return;
|
|
13
|
-
return articleRectObserver.init(el);
|
|
14
|
-
}, [el, articleRectObserver]);
|
|
15
|
-
|
|
16
|
-
return articleRectObserver;
|
|
17
|
-
};
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { ArticleRectObserver } from './ArticleRectObserver';
|
|
3
|
+
|
|
4
|
+
export const useArticleRectObserver = (el?: HTMLElement | null) => {
|
|
5
|
+
const [articleRectObserver, setArticleRectObserver] = useState<ArticleRectObserver | null>(null);
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
setArticleRectObserver(new ArticleRectObserver());
|
|
9
|
+
}, []);
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!el || !articleRectObserver) return;
|
|
13
|
+
return articleRectObserver.init(el);
|
|
14
|
+
}, [el, articleRectObserver]);
|
|
15
|
+
|
|
16
|
+
return articleRectObserver;
|
|
17
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { useContext, useEffect } from 'react';
|
|
2
|
-
import { ArticleRectContext } from '../../provider/ArticleRectContext';
|
|
3
|
-
|
|
4
|
-
export const useSectionRegistry = ( sectionId: string, el?: HTMLElement | null) => {
|
|
5
|
-
const articleRectObserver = useContext(ArticleRectContext);
|
|
6
|
-
|
|
7
|
-
useEffect(() => {
|
|
8
|
-
if (!el || !articleRectObserver) return;
|
|
9
|
-
return articleRectObserver.register(el, sectionId);
|
|
10
|
-
}, [el, articleRectObserver]);
|
|
11
|
-
};
|
|
1
|
+
import { useContext, useEffect } from 'react';
|
|
2
|
+
import { ArticleRectContext } from '../../provider/ArticleRectContext';
|
|
3
|
+
|
|
4
|
+
export const useSectionRegistry = ( sectionId: string, el?: HTMLElement | null) => {
|
|
5
|
+
const articleRectObserver = useContext(ArticleRectContext);
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (!el || !articleRectObserver) return;
|
|
9
|
+
return articleRectObserver.register(el, sectionId);
|
|
10
|
+
}, [el, articleRectObserver]);
|
|
11
|
+
};
|
package/src/utils/CSSNumeric.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
const reCSSNumeric = /([+-]?(?:\d*\.\d|\d)\d*)(\w+)/;
|
|
2
|
-
|
|
3
|
-
interface CSSNumberValue {
|
|
4
|
-
value: number;
|
|
5
|
-
unit?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function parseCSSNumber(input: string): CSSNumberValue {
|
|
9
|
-
const match = reCSSNumeric.exec(input);
|
|
10
|
-
if (!match) return { value: Number.NaN };
|
|
11
|
-
return {
|
|
12
|
-
value: Number.parseFloat(match[1]),
|
|
13
|
-
unit: match[2]
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function formatCSSNumber(input: CSSNumberValue): string {
|
|
18
|
-
return `${input.value}${input.unit ?? ''}`;
|
|
19
|
-
}
|
|
1
|
+
const reCSSNumeric = /([+-]?(?:\d*\.\d|\d)\d*)(\w+)/;
|
|
2
|
+
|
|
3
|
+
interface CSSNumberValue {
|
|
4
|
+
value: number;
|
|
5
|
+
unit?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function parseCSSNumber(input: string): CSSNumberValue {
|
|
9
|
+
const match = reCSSNumeric.exec(input);
|
|
10
|
+
if (!match) return { value: Number.NaN };
|
|
11
|
+
return {
|
|
12
|
+
value: Number.parseFloat(match[1]),
|
|
13
|
+
unit: match[2]
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function formatCSSNumber(input: CSSNumberValue): string {
|
|
18
|
+
return `${input.value}${input.unit ?? ''}`;
|
|
19
|
+
}
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
export type Listener<P> = (payload: P) => void;
|
|
2
|
-
type Listeners<EventMap> = {
|
|
3
|
-
[E in keyof (EventMap)]?: Listener<EventMap[E]>[];
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
export abstract class EventEmitter<EventMap> {
|
|
7
|
-
protected listeners: Listeners<EventMap> = {};
|
|
8
|
-
|
|
9
|
-
on<E extends (keyof EventMap)>(
|
|
10
|
-
event: E,
|
|
11
|
-
listener: Listener<EventMap[E]>
|
|
12
|
-
): () => void {
|
|
13
|
-
if (!Array.isArray(this.listeners[event])) {
|
|
14
|
-
this.listeners[event] = [];
|
|
15
|
-
}
|
|
16
|
-
this.listeners[event]?.push(listener);
|
|
17
|
-
return () => {
|
|
18
|
-
this.off(event, listener);
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
off<E extends (keyof EventMap)>(
|
|
23
|
-
event: E,
|
|
24
|
-
listener: Listener<EventMap[E]>
|
|
25
|
-
): void {
|
|
26
|
-
const filtered = this.listeners[event]?.filter(l => l !== listener);
|
|
27
|
-
this.listeners[event] = filtered && filtered.length > 0 ? filtered : undefined;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
protected emit<E extends (keyof EventMap)>(event: E, payload: EventMap[E]): void {
|
|
31
|
-
const listeners = this.listeners[event];
|
|
32
|
-
if (!Array.isArray(listeners)) return;
|
|
33
|
-
for (const listener of listeners) {
|
|
34
|
-
try {
|
|
35
|
-
listener(payload);
|
|
36
|
-
} catch (error) {
|
|
37
|
-
console.error(error instanceof Error ? error.stack : error);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
1
|
+
export type Listener<P> = (payload: P) => void;
|
|
2
|
+
type Listeners<EventMap> = {
|
|
3
|
+
[E in keyof (EventMap)]?: Listener<EventMap[E]>[];
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export abstract class EventEmitter<EventMap> {
|
|
7
|
+
protected listeners: Listeners<EventMap> = {};
|
|
8
|
+
|
|
9
|
+
on<E extends (keyof EventMap)>(
|
|
10
|
+
event: E,
|
|
11
|
+
listener: Listener<EventMap[E]>
|
|
12
|
+
): () => void {
|
|
13
|
+
if (!Array.isArray(this.listeners[event])) {
|
|
14
|
+
this.listeners[event] = [];
|
|
15
|
+
}
|
|
16
|
+
this.listeners[event]?.push(listener);
|
|
17
|
+
return () => {
|
|
18
|
+
this.off(event, listener);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
off<E extends (keyof EventMap)>(
|
|
23
|
+
event: E,
|
|
24
|
+
listener: Listener<EventMap[E]>
|
|
25
|
+
): void {
|
|
26
|
+
const filtered = this.listeners[event]?.filter(l => l !== listener);
|
|
27
|
+
this.listeners[event] = filtered && filtered.length > 0 ? filtered : undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
protected emit<E extends (keyof EventMap)>(event: E, payload: EventMap[E]): void {
|
|
31
|
+
const listeners = this.listeners[event];
|
|
32
|
+
if (!Array.isArray(listeners)) return;
|
|
33
|
+
for (const listener of listeners) {
|
|
34
|
+
try {
|
|
35
|
+
listener(payload);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error(error instanceof Error ? error.stack : error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|