yet-another-react-lightbox 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.
- package/LICENSE +21 -0
- package/README.md +63 -0
- package/dist/Lightbox.d.ts +49 -0
- package/dist/Lightbox.js +29 -0
- package/dist/core/components/IconButton.d.ts +6 -0
- package/dist/core/components/IconButton.js +4 -0
- package/dist/core/components/Icons.d.ts +25 -0
- package/dist/core/components/Icons.js +14 -0
- package/dist/core/components/ImageSlide.d.ts +5 -0
- package/dist/core/components/ImageSlide.js +60 -0
- package/dist/core/components/index.d.ts +3 -0
- package/dist/core/components/index.js +3 -0
- package/dist/core/config.d.ts +7 -0
- package/dist/core/config.js +70 -0
- package/dist/core/contexts/Events.d.ts +16 -0
- package/dist/core/contexts/Events.js +31 -0
- package/dist/core/contexts/Timeouts.d.ts +8 -0
- package/dist/core/contexts/Timeouts.js +35 -0
- package/dist/core/contexts/index.d.ts +2 -0
- package/dist/core/contexts/index.js +2 -0
- package/dist/core/hooks/index.d.ts +4 -0
- package/dist/core/hooks/index.js +4 -0
- package/dist/core/hooks/useContainerRect.d.ts +10 -0
- package/dist/core/hooks/useContainerRect.js +33 -0
- package/dist/core/hooks/useEnhancedEffect.d.ts +2 -0
- package/dist/core/hooks/useEnhancedEffect.js +2 -0
- package/dist/core/hooks/useLatest.d.ts +2 -0
- package/dist/core/hooks/useLatest.js +6 -0
- package/dist/core/hooks/useSensors.d.ts +15 -0
- package/dist/core/hooks/useSensors.js +37 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.js +6 -0
- package/dist/core/modules/Carousel.d.ts +3 -0
- package/dist/core/modules/Carousel.js +34 -0
- package/dist/core/modules/Controller.d.ts +13 -0
- package/dist/core/modules/Controller.js +267 -0
- package/dist/core/modules/Core.d.ts +3 -0
- package/dist/core/modules/Core.js +6 -0
- package/dist/core/modules/Navigation.d.ts +14 -0
- package/dist/core/modules/Navigation.js +25 -0
- package/dist/core/modules/NoScroll.d.ts +3 -0
- package/dist/core/modules/NoScroll.js +22 -0
- package/dist/core/modules/Portal.d.ts +3 -0
- package/dist/core/modules/Portal.js +34 -0
- package/dist/core/modules/Toolbar.d.ts +3 -0
- package/dist/core/modules/Toolbar.js +10 -0
- package/dist/core/modules/index.d.ts +7 -0
- package/dist/core/modules/index.js +7 -0
- package/dist/core/utils.d.ts +8 -0
- package/dist/core/utils.js +17 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/plugins/Fullscreen.d.ts +30 -0
- package/dist/plugins/Fullscreen.js +108 -0
- package/dist/plugins/Inline.d.ts +10 -0
- package/dist/plugins/Inline.js +17 -0
- package/dist/plugins/Video.d.ts +21 -0
- package/dist/plugins/Video.js +44 -0
- package/dist/plugins/index.d.ts +3 -0
- package/dist/plugins/index.js +3 -0
- package/dist/styles.css +237 -0
- package/dist/types.d.ts +102 -0
- package/dist/types.js +61 -0
- package/package.json +105 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Igor Danchenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Yet Another React Lightbox
|
|
2
|
+
|
|
3
|
+
Modern lightbox component for React.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/yet-another-react-lightbox)
|
|
8
|
+
[](https://bundlephobia.com/package/yet-another-react-lightbox)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
|
|
11
|
+
Coming soon...
|
|
12
|
+
|
|
13
|
+
## Documentation
|
|
14
|
+
|
|
15
|
+
Coming soon...
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```shell
|
|
20
|
+
npm install yet-another-react-lightbox
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
or
|
|
24
|
+
|
|
25
|
+
```shell
|
|
26
|
+
yarn add yet-another-react-lightbox
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Minimal Setup Example
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
import * as React from "react";
|
|
33
|
+
import { Lightbox } from "yet-another-react-lightbox";
|
|
34
|
+
import "yet-another-react-lightbox/styles.css";
|
|
35
|
+
|
|
36
|
+
const Page = () => {
|
|
37
|
+
const [open, setOpen] = React.useState(false);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<>
|
|
41
|
+
<button type="button" onClick={() => setOpen(true)}>
|
|
42
|
+
Open Lightbox
|
|
43
|
+
</button>
|
|
44
|
+
|
|
45
|
+
<Lightbox
|
|
46
|
+
open={open}
|
|
47
|
+
close={() => setOpen(false)}
|
|
48
|
+
slides={[
|
|
49
|
+
{ src: "/image1.jpg" },
|
|
50
|
+
{ src: "/image2.jpg" },
|
|
51
|
+
{ src: "/image3.jpg" },
|
|
52
|
+
]}
|
|
53
|
+
/>
|
|
54
|
+
</>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default Page;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## License
|
|
62
|
+
|
|
63
|
+
MIT © [Igor Danchenko](https://github.com/igordanchenko)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { LightboxDefaultProps, LightboxProps } from "./types.js";
|
|
3
|
+
declare const LightboxComponent: {
|
|
4
|
+
(props: LightboxProps & typeof LightboxDefaultProps): JSX.Element | null;
|
|
5
|
+
propTypes: {
|
|
6
|
+
open: import("prop-types").Validator<boolean>;
|
|
7
|
+
close: import("prop-types").Validator<(...args: any[]) => any>;
|
|
8
|
+
index: import("prop-types").Validator<number>;
|
|
9
|
+
slides: import("prop-types").Validator<any[]>;
|
|
10
|
+
render: import("prop-types").Validator<import("prop-types").InferProps<{
|
|
11
|
+
slide: import("prop-types").Validator<(...args: any[]) => any>;
|
|
12
|
+
}>>;
|
|
13
|
+
plugins: import("prop-types").Validator<((...args: any[]) => any)[]>;
|
|
14
|
+
toolbar: import("prop-types").Validator<import("prop-types").InferProps<{
|
|
15
|
+
buttons: import("prop-types").Validator<(string | number | boolean | import("prop-types").ReactElementLike | import("prop-types").ReactNodeArray | null | undefined)[]>;
|
|
16
|
+
}>>;
|
|
17
|
+
labels: import("prop-types").Validator<import("prop-types").InferProps<{}>>;
|
|
18
|
+
carousel: import("prop-types").Validator<import("prop-types").InferProps<{
|
|
19
|
+
finite: import("prop-types").Validator<boolean>;
|
|
20
|
+
preload: import("prop-types").Validator<number>;
|
|
21
|
+
padding: import("prop-types").Validator<string | number>;
|
|
22
|
+
spacing: import("prop-types").Validator<string | number>;
|
|
23
|
+
}>>;
|
|
24
|
+
animation: import("prop-types").Validator<import("prop-types").InferProps<{
|
|
25
|
+
fade: import("prop-types").Validator<number>;
|
|
26
|
+
swipe: import("prop-types").Validator<number>;
|
|
27
|
+
}>>;
|
|
28
|
+
};
|
|
29
|
+
defaultProps: {
|
|
30
|
+
open: boolean;
|
|
31
|
+
close: () => void;
|
|
32
|
+
index: number;
|
|
33
|
+
slides: import("./types.js").Slide[];
|
|
34
|
+
render: import("./types.js").Render;
|
|
35
|
+
plugins: import("./types.js").Plugin[];
|
|
36
|
+
toolbar: import("./types.js").Toolbar;
|
|
37
|
+
labels: {};
|
|
38
|
+
animation: import("./types.js").Animation;
|
|
39
|
+
carousel: import("./types.js").Carousel;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
declare type ComponentProps<T> = T extends React.ComponentType<infer P> | React.Component<infer P> ? JSX.LibraryManagedAttributes<T, P> : never;
|
|
43
|
+
declare type MakePartial<T> = T extends object ? Partial<T> : T;
|
|
44
|
+
declare type NestedPartial<T extends object> = {
|
|
45
|
+
[P in keyof T]?: MakePartial<T[P]>;
|
|
46
|
+
};
|
|
47
|
+
declare type NestedOptional<T, K extends keyof T> = Omit<T, K> & NestedPartial<Pick<T, K>>;
|
|
48
|
+
export declare const Lightbox: (props: NestedOptional<ComponentProps<typeof LightboxComponent>, "carousel" | "animation" | "render">) => JSX.Element;
|
|
49
|
+
export {};
|
package/dist/Lightbox.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { LightboxDefaultProps, LightboxPropTypes } from "./types.js";
|
|
3
|
+
import { CarouselModule, ControllerModule, CoreModule, createNode, NavigationModule, NoScrollModule, PortalModule, ToolbarModule, withPlugins, } from "./core/index.js";
|
|
4
|
+
const renderNode = (node, props) => React.createElement(node.module.component, { key: node.module.name, ...props }, node.children?.map((child) => renderNode(child, props)));
|
|
5
|
+
const LightboxComponent = (props) => {
|
|
6
|
+
const { plugins } = props;
|
|
7
|
+
const { config, augmentation } = withPlugins([
|
|
8
|
+
createNode(PortalModule, [
|
|
9
|
+
createNode(NoScrollModule, [
|
|
10
|
+
createNode(ControllerModule, [
|
|
11
|
+
createNode(CarouselModule),
|
|
12
|
+
createNode(ToolbarModule),
|
|
13
|
+
createNode(NavigationModule),
|
|
14
|
+
]),
|
|
15
|
+
]),
|
|
16
|
+
]),
|
|
17
|
+
], plugins);
|
|
18
|
+
const augmentedProps = augmentation(props);
|
|
19
|
+
if (!augmentedProps.open)
|
|
20
|
+
return null;
|
|
21
|
+
return React.createElement(React.Fragment, null, renderNode(createNode(CoreModule, config), augmentedProps));
|
|
22
|
+
};
|
|
23
|
+
LightboxComponent.propTypes = LightboxPropTypes;
|
|
24
|
+
LightboxComponent.defaultProps = LightboxDefaultProps;
|
|
25
|
+
export const Lightbox = (props) => {
|
|
26
|
+
const { carousel, animation, render, ...restProps } = props;
|
|
27
|
+
const { carousel: defaultCarousel, animation: defaultAnimation, render: defaultRender, ...restDefaultProps } = LightboxDefaultProps;
|
|
28
|
+
return (React.createElement(LightboxComponent, { carousel: { ...defaultCarousel, ...carousel }, animation: { ...defaultAnimation, ...animation }, render: { ...defaultRender, ...render }, ...restDefaultProps, ...restProps }));
|
|
29
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export declare type IconButtonProps = Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "type" | "aria-label"> & {
|
|
3
|
+
label: string;
|
|
4
|
+
icon: React.ElementType;
|
|
5
|
+
};
|
|
6
|
+
export declare const IconButton: ({ label, className, icon: Icon, onClick, ...rest }: IconButtonProps) => JSX.Element;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { clsx, cssClass } from "../utils.js";
|
|
3
|
+
export const IconButton = ({ label, className, icon: Icon, onClick, ...rest }) => (React.createElement("button", { type: "button", "aria-label": label, className: clsx(cssClass("button"), className), onClick: onClick || undefined, ...rest },
|
|
4
|
+
React.createElement(Icon, { className: cssClass("icon") })));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export declare const createIcon: (name: string, glyph: React.ReactNode) => {
|
|
3
|
+
(props: React.SVGProps<SVGSVGElement>): JSX.Element;
|
|
4
|
+
displayName: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const CloseIcon: {
|
|
7
|
+
(props: React.SVGProps<SVGSVGElement>): JSX.Element;
|
|
8
|
+
displayName: string;
|
|
9
|
+
};
|
|
10
|
+
export declare const PreviousIcon: {
|
|
11
|
+
(props: React.SVGProps<SVGSVGElement>): JSX.Element;
|
|
12
|
+
displayName: string;
|
|
13
|
+
};
|
|
14
|
+
export declare const NextIcon: {
|
|
15
|
+
(props: React.SVGProps<SVGSVGElement>): JSX.Element;
|
|
16
|
+
displayName: string;
|
|
17
|
+
};
|
|
18
|
+
export declare const LoadingIcon: {
|
|
19
|
+
(props: React.SVGProps<SVGSVGElement>): JSX.Element;
|
|
20
|
+
displayName: string;
|
|
21
|
+
};
|
|
22
|
+
export declare const ErrorIcon: {
|
|
23
|
+
(props: React.SVGProps<SVGSVGElement>): JSX.Element;
|
|
24
|
+
displayName: string;
|
|
25
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export const createIcon = (name, glyph) => {
|
|
3
|
+
const icon = (props) => (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "24", height: "24", "aria-hidden": "true", focusable: "false", ...props },
|
|
4
|
+
React.createElement("g", { fill: "currentColor" },
|
|
5
|
+
React.createElement("path", { d: "M0 0h24v24H0z", fill: "none" }),
|
|
6
|
+
glyph)));
|
|
7
|
+
icon.displayName = name;
|
|
8
|
+
return icon;
|
|
9
|
+
};
|
|
10
|
+
export const CloseIcon = createIcon("Close", React.createElement("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }));
|
|
11
|
+
export const PreviousIcon = createIcon("Previous", React.createElement("path", { d: "M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" }));
|
|
12
|
+
export const NextIcon = createIcon("Next", React.createElement("path", { d: "M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" }));
|
|
13
|
+
export const LoadingIcon = createIcon("Loading", React.createElement(React.Fragment, null, Array.from({ length: 8 }).map((_, index, array) => (React.createElement("line", { key: index, x1: "12", y1: "6.5", x2: "12", y2: "1.8", strokeLinecap: "round", strokeWidth: "2.6", stroke: "currentColor", strokeOpacity: (1 / array.length) * (index + 1), transform: `rotate(${(360 / array.length) * index}, 12, 12)` })))));
|
|
14
|
+
export const ErrorIcon = createIcon("Error", React.createElement("path", { d: "M21.9,21.9l-8.49-8.49l0,0L3.59,3.59l0,0L2.1,2.1L0.69,3.51L3,5.83V19c0,1.1,0.9,2,2,2h13.17l2.31,2.31L21.9,21.9z M5,18 l3.5-4.5l2.5,3.01L12.17,15l3,3H5z M21,18.17L5.83,3H19c1.1,0,2,0.9,2,2V18.17z" }));
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { clsx, cssClass } from "../utils.js";
|
|
3
|
+
import { useLatest } from "../hooks/index.js";
|
|
4
|
+
import { ErrorIcon, LoadingIcon } from "./Icons.js";
|
|
5
|
+
import { useController } from "../modules/Controller.js";
|
|
6
|
+
export const ImageSlide = ({ slide: image }) => {
|
|
7
|
+
const [state, setState] = React.useState("loading");
|
|
8
|
+
const latestState = useLatest(state);
|
|
9
|
+
const imageRef = React.useRef(null);
|
|
10
|
+
const { containerRect } = useController();
|
|
11
|
+
const handleLoading = React.useCallback((img) => {
|
|
12
|
+
if (latestState.current === "complete") {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
("decode" in img ? img.decode() : Promise.resolve())
|
|
16
|
+
.catch(() => { })
|
|
17
|
+
.then(() => {
|
|
18
|
+
if (!img.parentNode) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
setState("complete");
|
|
22
|
+
});
|
|
23
|
+
}, [latestState]);
|
|
24
|
+
const setImageRef = React.useCallback((img) => {
|
|
25
|
+
imageRef.current = img;
|
|
26
|
+
if (img?.complete) {
|
|
27
|
+
handleLoading(img);
|
|
28
|
+
}
|
|
29
|
+
}, [handleLoading]);
|
|
30
|
+
const onLoad = React.useCallback((event) => {
|
|
31
|
+
handleLoading(event.currentTarget);
|
|
32
|
+
}, [handleLoading]);
|
|
33
|
+
const onError = React.useCallback(() => {
|
|
34
|
+
setState("error");
|
|
35
|
+
}, []);
|
|
36
|
+
return (React.createElement(React.Fragment, null,
|
|
37
|
+
React.createElement("img", { ref: setImageRef, onLoad: onLoad, onError: onError, className: clsx(cssClass("slide_image"), state !== "complete" && cssClass("slide_image_loading")), draggable: false, alt: image.title, ...(image.srcSet
|
|
38
|
+
? {
|
|
39
|
+
sizes: `${Math.ceil((Math.min(image.aspectRatio ? containerRect.height * image.aspectRatio : Number.MAX_VALUE, containerRect.width) /
|
|
40
|
+
window.innerWidth) *
|
|
41
|
+
100)}vw`,
|
|
42
|
+
srcSet: image.srcSet
|
|
43
|
+
.sort((a, b) => a.width - b.width)
|
|
44
|
+
.map((item) => `${item.src} ${item.width}w`)
|
|
45
|
+
.join(", "),
|
|
46
|
+
style: {
|
|
47
|
+
maxWidth: `${Math.max(...image.srcSet.map((x) => x.width))}px`,
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
: {
|
|
51
|
+
style: (imageRef.current?.naturalWidth ?? 0) > 0
|
|
52
|
+
? {
|
|
53
|
+
maxWidth: `${imageRef.current?.naturalWidth}px`,
|
|
54
|
+
}
|
|
55
|
+
: undefined,
|
|
56
|
+
}), src: image.src }),
|
|
57
|
+
state !== "complete" && (React.createElement("div", { className: cssClass("slide_placeholder") },
|
|
58
|
+
state === "loading" && (React.createElement(LoadingIcon, { className: clsx(cssClass("icon"), cssClass("slide_loading")) })),
|
|
59
|
+
state === "error" && React.createElement(ErrorIcon, { className: clsx(cssClass("icon"), cssClass("slide_error")) })))));
|
|
60
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Augmentation, Component, Module, Node, Plugin } from "../types.js";
|
|
2
|
+
export declare const createModule: (name: string, component: Component) => Module;
|
|
3
|
+
export declare const createNode: (module: Module, children?: Node[] | undefined) => Node;
|
|
4
|
+
export declare const withPlugins: (root: Node[], plugins?: Plugin[] | undefined) => {
|
|
5
|
+
config: Node[];
|
|
6
|
+
augmentation: Augmentation;
|
|
7
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export const createModule = (name, component) => ({
|
|
2
|
+
name,
|
|
3
|
+
component,
|
|
4
|
+
});
|
|
5
|
+
export const createNode = (module, children) => ({
|
|
6
|
+
module,
|
|
7
|
+
children,
|
|
8
|
+
});
|
|
9
|
+
const traverseNode = (node, target, apply) => {
|
|
10
|
+
if (node.module.name === target) {
|
|
11
|
+
return apply(node);
|
|
12
|
+
}
|
|
13
|
+
if (node.children) {
|
|
14
|
+
return [
|
|
15
|
+
createNode(node.module, node.children.flatMap((n) => traverseNode(n, target, apply) ?? [])),
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
return [node];
|
|
19
|
+
};
|
|
20
|
+
const traverse = (nodes, target, apply) => nodes.flatMap((node) => traverseNode(node, target, apply) ?? []);
|
|
21
|
+
export const withPlugins = (root, plugins) => {
|
|
22
|
+
let config = root;
|
|
23
|
+
const augmentations = [];
|
|
24
|
+
const addParent = (target, module) => {
|
|
25
|
+
if (target === "") {
|
|
26
|
+
config = [createNode(module, config)];
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
config = traverse(config, target, (node) => [createNode(module, [node])]);
|
|
30
|
+
};
|
|
31
|
+
const addChild = (target, module, precede) => {
|
|
32
|
+
config = traverse(config, target, (node) => [
|
|
33
|
+
createNode(node.module, [
|
|
34
|
+
...(precede ? [createNode(module)] : []),
|
|
35
|
+
...(node.children ?? []),
|
|
36
|
+
...(!precede ? [createNode(module)] : []),
|
|
37
|
+
]),
|
|
38
|
+
]);
|
|
39
|
+
};
|
|
40
|
+
const addSibling = (target, module, precede) => {
|
|
41
|
+
config = traverse(config, target, (node) => [
|
|
42
|
+
...(precede ? [createNode(module)] : []),
|
|
43
|
+
node,
|
|
44
|
+
...(!precede ? [createNode(module)] : []),
|
|
45
|
+
]);
|
|
46
|
+
};
|
|
47
|
+
const replace = (target, module) => {
|
|
48
|
+
config = traverse(config, target, (node) => [createNode(module, node.children)]);
|
|
49
|
+
};
|
|
50
|
+
const remove = (target) => {
|
|
51
|
+
config = traverse(config, target, (node) => node.children);
|
|
52
|
+
};
|
|
53
|
+
const augment = (augmentation) => {
|
|
54
|
+
augmentations.push(augmentation);
|
|
55
|
+
};
|
|
56
|
+
plugins?.forEach((plugin) => {
|
|
57
|
+
plugin({
|
|
58
|
+
addParent,
|
|
59
|
+
addChild,
|
|
60
|
+
addSibling,
|
|
61
|
+
replace,
|
|
62
|
+
remove,
|
|
63
|
+
augment,
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
config,
|
|
68
|
+
augmentation: (props) => augmentations.reduce((acc, augmentation) => augmentation(acc), props),
|
|
69
|
+
};
|
|
70
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export declare type Topic = string;
|
|
3
|
+
export declare type Callback = (topic: Topic, event?: unknown) => void;
|
|
4
|
+
export declare type Events = {
|
|
5
|
+
[key: string]: Callback[];
|
|
6
|
+
};
|
|
7
|
+
export declare type Subscribe = (topic: Topic, callback: Callback) => () => void;
|
|
8
|
+
export declare type Unsubscribe = (topic: Topic, callback: Callback) => void;
|
|
9
|
+
export declare type Publish = (topic: Topic, event?: unknown) => void;
|
|
10
|
+
export declare type EventsContextType = {
|
|
11
|
+
subscribe: Subscribe;
|
|
12
|
+
unsubscribe: Unsubscribe;
|
|
13
|
+
publish: Publish;
|
|
14
|
+
};
|
|
15
|
+
export declare const useEvents: () => EventsContextType;
|
|
16
|
+
export declare const EventsProvider: ({ children }: React.PropsWithChildren<{}>) => JSX.Element;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { makeUseContext } from "../utils.js";
|
|
3
|
+
const EventsContext = React.createContext(null);
|
|
4
|
+
export const useEvents = makeUseContext("useEvents", "EventsContext", EventsContext);
|
|
5
|
+
export const EventsProvider = ({ children }) => {
|
|
6
|
+
const subscriptions = React.useRef({});
|
|
7
|
+
const unsubscribe = (topic, callback) => {
|
|
8
|
+
if (subscriptions.current[topic]) {
|
|
9
|
+
subscriptions.current[topic] = subscriptions.current[topic].filter((cb) => cb !== callback);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const subscribe = (topic, callback) => {
|
|
13
|
+
if (!subscriptions.current[topic]) {
|
|
14
|
+
subscriptions.current[topic] = [];
|
|
15
|
+
}
|
|
16
|
+
subscriptions.current[topic].push(callback);
|
|
17
|
+
return () => unsubscribe(topic, callback);
|
|
18
|
+
};
|
|
19
|
+
const publish = (topic, event) => {
|
|
20
|
+
subscriptions.current[topic]?.forEach((callback) => callback(topic, event));
|
|
21
|
+
};
|
|
22
|
+
React.useEffect(() => () => {
|
|
23
|
+
subscriptions.current = {};
|
|
24
|
+
}, []);
|
|
25
|
+
const context = React.useRef({
|
|
26
|
+
subscribe,
|
|
27
|
+
unsubscribe,
|
|
28
|
+
publish,
|
|
29
|
+
});
|
|
30
|
+
return React.createElement(EventsContext.Provider, { value: context.current }, children);
|
|
31
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export declare type TimeoutsContextType = {
|
|
3
|
+
setTimeout: (func: () => void, time?: number) => number;
|
|
4
|
+
clearTimeout: (id?: number) => void;
|
|
5
|
+
clearTimeouts: () => void;
|
|
6
|
+
};
|
|
7
|
+
export declare const useTimeouts: () => TimeoutsContextType;
|
|
8
|
+
export declare const TimeoutsProvider: ({ children }: React.PropsWithChildren<{}>) => JSX.Element;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { makeUseContext } from "../utils.js";
|
|
3
|
+
const TimeoutsContext = React.createContext(null);
|
|
4
|
+
export const useTimeouts = makeUseContext("useTimeouts", "TimeoutsContext", TimeoutsContext);
|
|
5
|
+
export const TimeoutsProvider = ({ children }) => {
|
|
6
|
+
const timeouts = React.useRef([]);
|
|
7
|
+
const removeTimeout = (id) => {
|
|
8
|
+
timeouts.current.splice(0, timeouts.current.length, ...timeouts.current.filter((tid) => tid !== id));
|
|
9
|
+
};
|
|
10
|
+
const setTimeout = (func, time) => {
|
|
11
|
+
const id = window.setTimeout(() => {
|
|
12
|
+
removeTimeout(id);
|
|
13
|
+
func();
|
|
14
|
+
}, time);
|
|
15
|
+
timeouts.current.push(id);
|
|
16
|
+
return id;
|
|
17
|
+
};
|
|
18
|
+
const clearTimeout = (id) => {
|
|
19
|
+
if (typeof id !== "undefined") {
|
|
20
|
+
removeTimeout(id);
|
|
21
|
+
window.clearTimeout(id);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const clearTimeouts = () => {
|
|
25
|
+
timeouts.current.forEach((tid) => window.clearTimeout(tid));
|
|
26
|
+
timeouts.current.splice(0, timeouts.current.length);
|
|
27
|
+
};
|
|
28
|
+
React.useEffect(() => () => clearTimeouts(), []);
|
|
29
|
+
const context = React.useRef({
|
|
30
|
+
setTimeout,
|
|
31
|
+
clearTimeout,
|
|
32
|
+
clearTimeouts,
|
|
33
|
+
});
|
|
34
|
+
return React.createElement(TimeoutsContext.Provider, { value: context.current }, children);
|
|
35
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export declare type ContainerRect = {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
};
|
|
6
|
+
export declare const useContainerRect: <T extends HTMLElement = HTMLElement>() => {
|
|
7
|
+
setContainerRef: (node: T | null) => void;
|
|
8
|
+
containerRef: React.MutableRefObject<T | null>;
|
|
9
|
+
containerRect: ContainerRect | undefined;
|
|
10
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export const useContainerRect = () => {
|
|
3
|
+
const [containerRect, setContainerRect] = React.useState();
|
|
4
|
+
const containerRef = React.useRef(null);
|
|
5
|
+
const observerRef = React.useRef();
|
|
6
|
+
const setContainerRef = React.useCallback((node) => {
|
|
7
|
+
containerRef.current = node;
|
|
8
|
+
if (observerRef.current) {
|
|
9
|
+
observerRef.current.disconnect();
|
|
10
|
+
observerRef.current = undefined;
|
|
11
|
+
}
|
|
12
|
+
const updateContainerRect = () => {
|
|
13
|
+
const width = node?.clientWidth;
|
|
14
|
+
const height = node?.clientHeight;
|
|
15
|
+
setContainerRect(width !== undefined && height !== undefined
|
|
16
|
+
? {
|
|
17
|
+
width,
|
|
18
|
+
height,
|
|
19
|
+
}
|
|
20
|
+
: undefined);
|
|
21
|
+
};
|
|
22
|
+
updateContainerRect();
|
|
23
|
+
if (node && typeof ResizeObserver !== "undefined") {
|
|
24
|
+
observerRef.current = new ResizeObserver(updateContainerRect);
|
|
25
|
+
observerRef.current.observe(node);
|
|
26
|
+
}
|
|
27
|
+
}, []);
|
|
28
|
+
return React.useMemo(() => ({
|
|
29
|
+
setContainerRef,
|
|
30
|
+
containerRef,
|
|
31
|
+
containerRect,
|
|
32
|
+
}), [setContainerRef, containerRef, containerRect]);
|
|
33
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export declare type PointerEventType = "onPointerDown" | "onPointerMove" | "onPointerUp" | "onPointerLeave" | "onPointerCancel";
|
|
3
|
+
export declare type TouchEventType = "onTouchStart" | "onTouchMove" | "onTouchEnd" | "onTouchCancel";
|
|
4
|
+
export declare type KeyboardEventType = "onKeyDown" | "onKeyUp";
|
|
5
|
+
export declare type WheelEventType = "onWheel";
|
|
6
|
+
export declare type SupportedEventType = PointerEventType | TouchEventType | KeyboardEventType | WheelEventType;
|
|
7
|
+
export declare type ReactEventType<T, K extends SupportedEventType> = K extends TouchEventType ? React.TouchEvent<T> : K extends KeyboardEventType ? React.KeyboardEvent<T> : K extends WheelEventType ? React.WheelEvent<T> : K extends PointerEventType ? React.PointerEvent<T> : never;
|
|
8
|
+
export declare type EventCallback<T, P extends React.PointerEvent<T> | React.TouchEvent<T> | React.KeyboardEvent<T> | React.WheelEvent<T>> = (event: P) => void;
|
|
9
|
+
export declare type SubscribeSensors<T> = <ET extends SupportedEventType>(type: ET, callback: EventCallback<T, ReactEventType<T, ET>>) => () => void;
|
|
10
|
+
export declare type RegisterSensors<T> = Required<Pick<React.HTMLAttributes<T>, PointerEventType>> & Required<Pick<React.HTMLAttributes<T>, TouchEventType>> & Required<Pick<React.HTMLAttributes<T>, KeyboardEventType>> & Required<Pick<React.HTMLAttributes<T>, WheelEventType>>;
|
|
11
|
+
export declare type UseSensors<T> = {
|
|
12
|
+
registerSensors: RegisterSensors<T>;
|
|
13
|
+
subscribeSensors: SubscribeSensors<T>;
|
|
14
|
+
};
|
|
15
|
+
export declare const useSensors: <T extends Element>() => UseSensors<T>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export const useSensors = () => {
|
|
3
|
+
const [subscribers] = React.useState({});
|
|
4
|
+
return React.useMemo(() => {
|
|
5
|
+
const notifySubscribers = (type, event) => {
|
|
6
|
+
subscribers[type]?.forEach((listener) => listener(event));
|
|
7
|
+
};
|
|
8
|
+
return {
|
|
9
|
+
registerSensors: {
|
|
10
|
+
onPointerDown: (event) => notifySubscribers("onPointerDown", event),
|
|
11
|
+
onPointerMove: (event) => notifySubscribers("onPointerMove", event),
|
|
12
|
+
onPointerUp: (event) => notifySubscribers("onPointerUp", event),
|
|
13
|
+
onPointerLeave: (event) => notifySubscribers("onPointerLeave", event),
|
|
14
|
+
onPointerCancel: (event) => notifySubscribers("onPointerCancel", event),
|
|
15
|
+
onTouchStart: (event) => notifySubscribers("onTouchStart", event),
|
|
16
|
+
onTouchMove: (event) => notifySubscribers("onTouchMove", event),
|
|
17
|
+
onTouchEnd: (event) => notifySubscribers("onTouchEnd", event),
|
|
18
|
+
onTouchCancel: (event) => notifySubscribers("onTouchCancel", event),
|
|
19
|
+
onKeyDown: (event) => notifySubscribers("onKeyDown", event),
|
|
20
|
+
onKeyUp: (event) => notifySubscribers("onKeyUp", event),
|
|
21
|
+
onWheel: (event) => notifySubscribers("onWheel", event),
|
|
22
|
+
},
|
|
23
|
+
subscribeSensors: (type, callback) => {
|
|
24
|
+
if (!subscribers[type]) {
|
|
25
|
+
subscribers[type] = [];
|
|
26
|
+
}
|
|
27
|
+
subscribers[type]?.push(callback);
|
|
28
|
+
return () => {
|
|
29
|
+
const listeners = subscribers[type];
|
|
30
|
+
if (listeners) {
|
|
31
|
+
listeners.splice(0, listeners.length, ...listeners.filter((el) => el !== callback));
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}, [subscribers]);
|
|
37
|
+
};
|