@gohanfromgoku/ui-kit 0.1.2 → 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/dist/components/Button/index.js +6 -5
- package/dist/components/Image/index.js +6 -5
- package/dist/components/Input/index.js +9 -7
- package/dist/components/Text/index.js +9 -7
- package/dist/components/Tooltip/index.js +9 -7
- package/dist/hooks/useHandleClickOutside.js +1 -1
- package/dist/hooks/useQueryParams.js +5 -7
- package/dist/hooks/useWindowSize.js +1 -1
- package/dist/navigation/createBrowserRouter.js +76 -0
- package/dist/navigation/createMemoryRouter.js +55 -0
- package/dist/navigation/index.js +2 -4
- package/dist/navigation/{extractParamsFromURL.js → support/params.support.js} +1 -2
- package/dist/navigation/support/query-params.support.js +43 -0
- package/dist/navigation/support/url.support.js +20 -0
- package/dist/prototypes/copyToClipboard.js +2 -1
- package/dist/prototypes/index.js +2 -0
- package/dist/prototypes/stringCapitalize.js +4 -0
- package/dist/storage/index.js +32 -47
- package/dist/translations/index.js +35 -30
- package/package.json +4 -5
- package/types/components/Button/index.d.ts +5 -7
- package/types/components/Image/index.d.ts +4 -6
- package/types/components/Input/index.d.ts +4 -4
- package/types/components/Text/index.d.ts +2 -4
- package/types/components/Tooltip/index.d.ts +4 -4
- package/types/hooks/useHandleClickOutside.d.ts +2 -2
- package/types/hooks/useQueryParams.d.ts +8 -1
- package/types/navigation/createBrowserRouter.d.ts +33 -0
- package/types/navigation/createMemoryRouter.d.ts +52 -0
- package/types/navigation/index.d.ts +2 -4
- package/types/navigation/{extractQueryParamsFromURL.d.ts → support/query-params.support.d.ts} +1 -0
- package/types/navigation/support/url.support.d.ts +2 -0
- package/types/prototypes/copyToClipboard.d.ts +1 -1
- package/types/prototypes/index.d.ts +2 -1
- package/types/prototypes/stringCapitalize.d.ts +2 -0
- package/types/storage/index.d.ts +4 -7
- package/types/translations/index.d.ts +12 -5
- package/dist/navigation/Outlet.js +0 -26
- package/dist/navigation/Page404.js +0 -2
- package/dist/navigation/createRoutes.js +0 -16
- package/dist/navigation/extractQueryParamsFromURL.js +0 -24
- package/dist/navigation/isRouteMatching.js +0 -15
- package/dist/navigation/navigate.js +0 -41
- package/dist/navigation/navigation.store.js +0 -4
- package/dist/navigation/useLocationDetails.js +0 -10
- package/types/navigation/Outlet.d.ts +0 -7
- package/types/navigation/Page404.d.ts +0 -1
- package/types/navigation/createRoutes.d.ts +0 -7
- package/types/navigation/isRouteMatching.d.ts +0 -5
- package/types/navigation/navigate.d.ts +0 -6
- package/types/navigation/navigation.store.d.ts +0 -46
- package/types/navigation/useLocationDetails.d.ts +0 -5
- /package/types/navigation/{extractParamsFromURL.d.ts → support/params.support.d.ts} +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { jsx as _jsx } from "
|
|
2
|
-
import { memo, forwardRef } from "preact/compat";
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
2
|
import { checkProps } from "../../helpers/index";
|
|
3
|
+
import { forwardRef, memo } from "react";
|
|
4
4
|
const defaultProps = {
|
|
5
5
|
onClick: () => { },
|
|
6
6
|
disabled: false,
|
|
7
7
|
className: "",
|
|
8
8
|
type: "button",
|
|
9
9
|
};
|
|
10
|
-
const Button = forwardRef((props, ref) => {
|
|
10
|
+
const Button = memo(forwardRef((props, ref) => {
|
|
11
11
|
const { children, className, onClick, disabled, type, ...rest } = { ...defaultProps, ...props };
|
|
12
12
|
return (_jsx("button", { ref: ref, className: className, disabled: disabled, type: type, onClick: (event) => {
|
|
13
13
|
if (type === "button" || !type) {
|
|
@@ -17,5 +17,6 @@ const Button = forwardRef((props, ref) => {
|
|
|
17
17
|
onClick(event);
|
|
18
18
|
}
|
|
19
19
|
}, ...rest, children: children }));
|
|
20
|
-
});
|
|
21
|
-
|
|
20
|
+
}), checkProps);
|
|
21
|
+
Button.displayName = "Button";
|
|
22
|
+
export default Button;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { jsx as _jsx } from "
|
|
2
|
-
import { forwardRef, memo } from "
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, memo } from "react";
|
|
3
3
|
import { checkProps } from "../../helpers/index";
|
|
4
4
|
const defaultProps = {
|
|
5
5
|
altImage: null,
|
|
@@ -8,12 +8,13 @@ const defaultProps = {
|
|
|
8
8
|
priority: true,
|
|
9
9
|
onClick: () => { }
|
|
10
10
|
};
|
|
11
|
-
const Image = forwardRef((props, ref) => {
|
|
11
|
+
const Image = memo(forwardRef((props, ref) => {
|
|
12
12
|
const { altImage, className, src, priority, onClick, alt, ...rest } = { ...defaultProps, ...props };
|
|
13
13
|
return (_jsx("img", { src: src, ref: ref, width: "100%", height: "100%", onClick: (event) => { event.preventDefault(); onClick(event); }, draggable: false, onError: async () => {
|
|
14
14
|
if (ref && 'current' in ref && ref.current) {
|
|
15
15
|
ref.current.src = altImage || "";
|
|
16
16
|
}
|
|
17
17
|
}, alt: alt, className: className, fetchPriority: priority ? "high" : "auto", loading: priority ? "eager" : "lazy", ...rest }));
|
|
18
|
-
});
|
|
19
|
-
|
|
18
|
+
}), checkProps);
|
|
19
|
+
Image.displayName = "Image";
|
|
20
|
+
export default Image;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx } from "
|
|
2
|
-
import { memo } from "
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, memo } from "react";
|
|
3
3
|
import { checkProps } from "../../helpers/index";
|
|
4
|
-
import {
|
|
4
|
+
import { useTranslations } from "../../translations/index";
|
|
5
5
|
const defaultProps = {
|
|
6
6
|
onChange: () => { },
|
|
7
7
|
className: "",
|
|
@@ -9,8 +9,10 @@ const defaultProps = {
|
|
|
9
9
|
type: "text",
|
|
10
10
|
name: ""
|
|
11
11
|
};
|
|
12
|
-
const Input = (props) => {
|
|
12
|
+
const Input = memo(forwardRef((props, ref) => {
|
|
13
|
+
const { translate } = useTranslations();
|
|
13
14
|
const { onChange, className, placeholder, type, name, ...rest } = { ...defaultProps, ...props };
|
|
14
|
-
return _jsx("input", { className: className, placeholder: translate(placeholder), type: type, name: name, onChange: event => onChange(event.currentTarget.value, event), ...rest });
|
|
15
|
-
};
|
|
16
|
-
|
|
15
|
+
return _jsx("input", { className: className, placeholder: translate(placeholder), type: type, ref: ref, name: name, onChange: event => onChange(event.currentTarget.value, event), ...rest });
|
|
16
|
+
}), checkProps);
|
|
17
|
+
Input.displayName = "Input";
|
|
18
|
+
export default Input;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx } from "
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { checkProps } from "../../helpers/index";
|
|
3
|
-
import {
|
|
4
|
-
import { forwardRef, memo
|
|
3
|
+
import { useTranslations } from "../../translations/index";
|
|
4
|
+
import { forwardRef, memo } from "react";
|
|
5
5
|
const defaultProps = {
|
|
6
6
|
text: "",
|
|
7
7
|
data: {},
|
|
@@ -10,12 +10,14 @@ const defaultProps = {
|
|
|
10
10
|
tag: "span",
|
|
11
11
|
onClick: () => { },
|
|
12
12
|
};
|
|
13
|
-
const Text = forwardRef((props, ref) => {
|
|
13
|
+
const Text = memo(forwardRef((props, ref) => {
|
|
14
|
+
const { translate } = useTranslations();
|
|
14
15
|
const { text, data, html, className, tag: Tag, onClick, ...rest } = { ...defaultProps, ...props };
|
|
15
|
-
const translated =
|
|
16
|
+
const translated = translate(text, data);
|
|
16
17
|
if (html) {
|
|
17
18
|
return (_jsx(Tag, { ...rest, ref: ref, dangerouslySetInnerHTML: { __html: translated }, className: className, onClick: (event) => { event.preventDefault(); onClick(event); } }));
|
|
18
19
|
}
|
|
19
20
|
return (_jsx(Tag, { ...rest, ref: ref, className: className, onClick: (event) => { event.preventDefault(); onClick(event); }, children: translated }));
|
|
20
|
-
});
|
|
21
|
-
|
|
21
|
+
}), checkProps);
|
|
22
|
+
Text.displayName = "Text";
|
|
23
|
+
export default Text;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { jsx as _jsx } from "
|
|
2
|
-
import { useEffect, useRef } from "
|
|
3
|
-
import { memo } from "
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { memo } from "react";
|
|
4
4
|
import { checkProps, toast } from "../../helpers/index";
|
|
5
|
-
import {
|
|
5
|
+
import { useTranslations } from "../../translations/index";
|
|
6
6
|
const isTouchDevice = () => typeof window !== "undefined" && "ontouchstart" in window;
|
|
7
7
|
const styles = {
|
|
8
8
|
width: "fit-content",
|
|
9
9
|
height: "fit-content"
|
|
10
10
|
};
|
|
11
|
-
const Tooltip = ({ message, children, className }) => {
|
|
11
|
+
const Tooltip = memo(({ message, children, className }) => {
|
|
12
|
+
const { translate } = useTranslations();
|
|
12
13
|
const ref = useRef(null);
|
|
13
14
|
const toastRef = useRef(null);
|
|
14
15
|
useEffect(() => {
|
|
@@ -48,5 +49,6 @@ const Tooltip = ({ message, children, className }) => {
|
|
|
48
49
|
else
|
|
49
50
|
toastRef.current = toast(translate(message), ref.current, 2000);
|
|
50
51
|
}, children: children }));
|
|
51
|
-
};
|
|
52
|
-
|
|
52
|
+
}, checkProps);
|
|
53
|
+
Tooltip.displayName = "Tooltip";
|
|
54
|
+
export default Tooltip;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
const queryParamsSignal =
|
|
1
|
+
import createStore from "../storage/index";
|
|
2
|
+
const { queryParamsSignal } = createStore("queryParamsSignal", { value: {} });
|
|
3
3
|
const getParams = () => {
|
|
4
4
|
const search = window.location.search.slice(1);
|
|
5
5
|
const params = new URLSearchParams(search);
|
|
@@ -8,10 +8,8 @@ const getParams = () => {
|
|
|
8
8
|
obj[key] = value;
|
|
9
9
|
return obj;
|
|
10
10
|
};
|
|
11
|
-
queryParamsSignal.value
|
|
12
|
-
window.addEventListener("popstate", () => {
|
|
13
|
-
queryParamsSignal.value = getParams();
|
|
14
|
-
});
|
|
11
|
+
queryParamsSignal.setState({ value: getParams() });
|
|
12
|
+
window.addEventListener("popstate", () => { queryParamsSignal.setState({ value: getParams() }); });
|
|
15
13
|
export const setQueryParams = (updates, { replace = false, pathname } = {}) => {
|
|
16
14
|
const params = new URLSearchParams();
|
|
17
15
|
Object.entries(updates).forEach(([key, value]) => {
|
|
@@ -26,6 +24,6 @@ export const setQueryParams = (updates, { replace = false, pathname } = {}) => {
|
|
|
26
24
|
window.history.replaceState({}, "", newUrl);
|
|
27
25
|
else
|
|
28
26
|
window.history.pushState({}, "", newUrl);
|
|
29
|
-
queryParamsSignal.value
|
|
27
|
+
queryParamsSignal.setState({ value: getParams() });
|
|
30
28
|
};
|
|
31
29
|
export { queryParamsSignal as queryParams };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useLayoutEffect, useMemo, useState } from "
|
|
1
|
+
import { useLayoutEffect, useMemo, useState } from "react";
|
|
2
2
|
const useWindowSize = () => {
|
|
3
3
|
const [size, setSize] = useState({ height: window.innerHeight, width: window.innerWidth });
|
|
4
4
|
useLayoutEffect(() => {
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import createStore from "../storage/index";
|
|
4
|
+
import { generateURLToNavigate, isRouteMatching } from "./support/url.support";
|
|
5
|
+
import { extractParamsFromURL } from "./support/params.support";
|
|
6
|
+
import { extractQueryParamsFromURL } from "./support/query-params.support";
|
|
7
|
+
// Initialize stores
|
|
8
|
+
const { locationDetails } = createStore("locationDetails", {
|
|
9
|
+
value: { params: {}, queryParams: {}, ...window.location }
|
|
10
|
+
});
|
|
11
|
+
const { activeRoute } = createStore("activeRoute", {
|
|
12
|
+
value: {}
|
|
13
|
+
});
|
|
14
|
+
const createBrowserRouter = (routes, { page404 } = { page404: () => _jsx(_Fragment, { children: "Page Not Found" }) }) => {
|
|
15
|
+
// Navigate function
|
|
16
|
+
const navigate = (to, { queryParams, replace } = {}) => {
|
|
17
|
+
if (typeof to === "number") {
|
|
18
|
+
window.history.go(to);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const url = generateURLToNavigate(to, queryParams || {});
|
|
22
|
+
if (window.location.href === url)
|
|
23
|
+
return;
|
|
24
|
+
if (replace) {
|
|
25
|
+
window.history.replaceState({}, "", url);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
window.history.pushState({}, "", url);
|
|
29
|
+
}
|
|
30
|
+
// Trigger update
|
|
31
|
+
window.dispatchEvent(new Event("popstate"));
|
|
32
|
+
};
|
|
33
|
+
// Hook to get current location details
|
|
34
|
+
const useLocationDetails = () => {
|
|
35
|
+
if (routes.length === 0) {
|
|
36
|
+
throw new Error("useLocationDetails cannot be used without initializing routes. Use createBrowserRouter with routes.");
|
|
37
|
+
}
|
|
38
|
+
const [state, setState] = useState(locationDetails.value);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const update = () => setState(locationDetails.value);
|
|
41
|
+
window.addEventListener("popstate", update);
|
|
42
|
+
return () => window.removeEventListener("popstate", update);
|
|
43
|
+
}, []);
|
|
44
|
+
return state;
|
|
45
|
+
};
|
|
46
|
+
// Outlet component
|
|
47
|
+
const Outlet = () => {
|
|
48
|
+
const [, setRender] = useState(0);
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
const updateLocation = () => {
|
|
51
|
+
// Find active route
|
|
52
|
+
const active = routes.find(r => isRouteMatching(r.pathname)) ||
|
|
53
|
+
{ pathname: window.location.pathname, component: page404 };
|
|
54
|
+
activeRoute.setState({ value: active });
|
|
55
|
+
// Update location details
|
|
56
|
+
const params = extractParamsFromURL(window.location.pathname, active.pathname);
|
|
57
|
+
const queryParams = extractQueryParamsFromURL(window.location.href);
|
|
58
|
+
locationDetails.setState({ value: { params, queryParams, ...window.location } });
|
|
59
|
+
// Force re-render
|
|
60
|
+
setRender(r => r + 1);
|
|
61
|
+
};
|
|
62
|
+
// Initial update
|
|
63
|
+
updateLocation();
|
|
64
|
+
window.addEventListener("popstate", updateLocation);
|
|
65
|
+
return () => window.removeEventListener("popstate", updateLocation);
|
|
66
|
+
}, []);
|
|
67
|
+
const Component = activeRoute.value?.component ?? page404;
|
|
68
|
+
return _jsx(Component, {});
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
navigate,
|
|
72
|
+
useLocationDetails,
|
|
73
|
+
Outlet
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
export default createBrowserRouter;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import {} from "react";
|
|
3
|
+
import createStore from "../storage/index";
|
|
4
|
+
import { generateURLToNavigate, isRouteMatching } from "./support/url.support";
|
|
5
|
+
import { extractParamsFromURL } from "./support/params.support";
|
|
6
|
+
import { extractQueryParamsFromURL } from "./support/query-params.support";
|
|
7
|
+
const createMemoryRouter = (routes, { page404 } = { page404: () => _jsx(_Fragment, { children: "Page Not Found" }) }) => {
|
|
8
|
+
if (routes.length === 0) {
|
|
9
|
+
throw "Atleast one route should present";
|
|
10
|
+
}
|
|
11
|
+
;
|
|
12
|
+
const { activeRoute } = createStore("activeRoute", routes.find(() => isRouteMatching("/")) || { pathname: "/", component: page404 });
|
|
13
|
+
const { locationDetails } = createStore("locationDetails", { params: {}, queryParams: {}, ...window.location, pathname: activeRoute.pathname });
|
|
14
|
+
const { entries } = createStore("entries", { value: ["/"] });
|
|
15
|
+
const { currentIndex } = createStore("currentIndex", { value: 0 });
|
|
16
|
+
const navigate = (to, { queryParams } = {}) => {
|
|
17
|
+
if (typeof to === "number") {
|
|
18
|
+
const targetIndex = currentIndex.value + to;
|
|
19
|
+
if (targetIndex < 0 || targetIndex >= entries.value.length)
|
|
20
|
+
return;
|
|
21
|
+
const raw = entries.value[targetIndex];
|
|
22
|
+
const url = raw.startsWith("http") ? new URL(raw).pathname + new URL(raw).search : raw;
|
|
23
|
+
currentIndex.setState({ value: targetIndex });
|
|
24
|
+
const active = routes.find(r => isRouteMatching(r.pathname, url)) || { pathname: url, component: page404 };
|
|
25
|
+
activeRoute.setState(active);
|
|
26
|
+
const params = extractParamsFromURL(url, active.pathname);
|
|
27
|
+
const allQueryParams = extractQueryParamsFromURL(url);
|
|
28
|
+
locationDetails.setState({ params, queryParams: allQueryParams, ...window.location, pathname: active.pathname });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const url = generateURLToNavigate(to, queryParams || {});
|
|
32
|
+
if (activeRoute.pathname === url)
|
|
33
|
+
return;
|
|
34
|
+
entries.setState({ value: [...entries.value, url] });
|
|
35
|
+
const active = routes.find(r => isRouteMatching(r.pathname, to)) || { pathname: to, component: page404 };
|
|
36
|
+
activeRoute.setState(active);
|
|
37
|
+
const params = extractParamsFromURL(to, activeRoute.pathname);
|
|
38
|
+
const allQueryParams = extractQueryParamsFromURL(url);
|
|
39
|
+
locationDetails.setState({ params, queryParams: allQueryParams, ...window.location, pathname: active.pathname });
|
|
40
|
+
currentIndex.setState({ value: currentIndex.value + 1 });
|
|
41
|
+
};
|
|
42
|
+
const useLocationDetails = () => {
|
|
43
|
+
return locationDetails;
|
|
44
|
+
};
|
|
45
|
+
const Outlet = () => {
|
|
46
|
+
const Component = activeRoute.component;
|
|
47
|
+
return _jsx(Component, {});
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
navigate,
|
|
51
|
+
useLocationDetails,
|
|
52
|
+
Outlet
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
export default createMemoryRouter;
|
package/dist/navigation/index.js
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
export { default as
|
|
2
|
-
export { default as
|
|
3
|
-
export { default as navigate } from "./navigate";
|
|
4
|
-
export { default as useLocationDetails } from "./useLocationDetails";
|
|
1
|
+
export { default as createBrowserRouter } from "./createBrowserRouter";
|
|
2
|
+
export { default as createMemoryRouter } from "./createMemoryRouter";
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const extractParamsFromURL = (url, compareWith) => {
|
|
5
5
|
const params = {};
|
|
6
|
-
const
|
|
7
|
-
const parts = href.split("?");
|
|
6
|
+
const parts = url.split("?");
|
|
8
7
|
if (parts.length > 2) {
|
|
9
8
|
throw "Invalid URL";
|
|
10
9
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @internal
|
|
3
|
+
*/
|
|
4
|
+
export const createQueryParamsSearchString = (queryParams) => {
|
|
5
|
+
const keys = Object.keys(queryParams);
|
|
6
|
+
if (keys.length > 0) {
|
|
7
|
+
let search = "?";
|
|
8
|
+
for (let index = 0; index < keys.length; index++) {
|
|
9
|
+
const key = keys[index];
|
|
10
|
+
search = `${search}${key}=${queryParams[key]}`;
|
|
11
|
+
if (index !== keys.length - 1) {
|
|
12
|
+
search = search + "&";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return search;
|
|
16
|
+
}
|
|
17
|
+
return "";
|
|
18
|
+
};
|
|
19
|
+
export const extractQueryParamsFromURL = (url) => {
|
|
20
|
+
const queryObj = {};
|
|
21
|
+
const parts = url.split("?");
|
|
22
|
+
if (parts.length > 2) {
|
|
23
|
+
throw "Invalid URL";
|
|
24
|
+
}
|
|
25
|
+
;
|
|
26
|
+
if (parts.length === 1) {
|
|
27
|
+
return queryObj;
|
|
28
|
+
}
|
|
29
|
+
;
|
|
30
|
+
const search = parts[1];
|
|
31
|
+
if (search && search.length > 0) {
|
|
32
|
+
const queries = search.split("&");
|
|
33
|
+
for (const query of queries) {
|
|
34
|
+
const queryParts = query.split("=");
|
|
35
|
+
if (queryParts.length > 2) {
|
|
36
|
+
throw "Invalid URL";
|
|
37
|
+
}
|
|
38
|
+
const [key, value] = queryParts;
|
|
39
|
+
queryObj[decodeURIComponent(key)] = decodeURIComponent(value ?? "");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return queryObj;
|
|
43
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createQueryParamsSearchString, extractQueryParamsFromURL } from "./query-params.support";
|
|
2
|
+
export const generateURLToNavigate = (pathname, queryParams) => {
|
|
3
|
+
const queryParamsFromPathname = extractQueryParamsFromURL(pathname);
|
|
4
|
+
const allQueryParams = createQueryParamsSearchString({ ...queryParamsFromPathname, ...queryParams });
|
|
5
|
+
const url = pathname.startsWith("/") ? `${window.location.origin}${pathname.split("?")[0]}` : `${window.location.origin}/${pathname.split("?")[0]}`;
|
|
6
|
+
const path = `${url}${allQueryParams}`;
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
export const isRouteMatching = (routePath, comparePath) => {
|
|
10
|
+
const current = comparePath ?? window.location.pathname;
|
|
11
|
+
if (routePath === "/" || routePath === "") {
|
|
12
|
+
const isRoot = current === "/" || current === "/index.html" || current === "";
|
|
13
|
+
return isRoot;
|
|
14
|
+
}
|
|
15
|
+
const routeParts = routePath.split("/").filter(Boolean);
|
|
16
|
+
const currentParts = current.split("/").filter(Boolean);
|
|
17
|
+
if (routeParts.length !== currentParts.length)
|
|
18
|
+
return false;
|
|
19
|
+
return routeParts.every((part, i) => part.startsWith(":") || part === currentParts[i]);
|
|
20
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import toast from "../helpers/toast";
|
|
2
|
-
const copyToClipboard = async (
|
|
2
|
+
const copyToClipboard = async function (message = "Copied") {
|
|
3
|
+
const text = this;
|
|
3
4
|
try {
|
|
4
5
|
if (navigator.clipboard && window.isSecureContext) {
|
|
5
6
|
await navigator.clipboard.writeText(text);
|
package/dist/prototypes/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import copyToClipboard from "./copyToClipboard";
|
|
2
2
|
import maskString from "./maskString";
|
|
3
|
+
import capitalize from "./stringCapitalize";
|
|
3
4
|
if (!String.prototype.copy) {
|
|
4
5
|
String.prototype.copy = copyToClipboard;
|
|
5
6
|
String.prototype.mask = maskString;
|
|
7
|
+
String.prototype.capitalize = capitalize;
|
|
6
8
|
}
|
package/dist/storage/index.js
CHANGED
|
@@ -1,51 +1,36 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
state.value = { ...state.value, ...values };
|
|
15
|
-
if (persist.length) {
|
|
16
|
-
const toStore = persist.reduce((acc, key) => {
|
|
17
|
-
acc[key] = state.value[key];
|
|
18
|
-
return acc;
|
|
19
|
-
}, {});
|
|
20
|
-
localStorage.setItem(name, JSON.stringify(toStore));
|
|
21
|
-
}
|
|
1
|
+
import "../prototypes";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
export default function createStore(name, initialState) {
|
|
4
|
+
let state = initialState;
|
|
5
|
+
const listeners = new Set();
|
|
6
|
+
const subscribe = (listener) => {
|
|
7
|
+
listeners.add(listener);
|
|
8
|
+
return () => listeners.delete(listener);
|
|
9
|
+
};
|
|
10
|
+
const getSnapshot = () => state;
|
|
11
|
+
const setState = (partial) => {
|
|
12
|
+
state = { ...state, ...partial };
|
|
13
|
+
listeners.forEach(l => l());
|
|
22
14
|
};
|
|
23
15
|
const resetState = () => {
|
|
24
|
-
state
|
|
25
|
-
|
|
16
|
+
state = initialState;
|
|
17
|
+
listeners.forEach(l => l());
|
|
26
18
|
};
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const toStore = persist.reduce((acc, key) => {
|
|
42
|
-
acc[key] = state.value[key];
|
|
43
|
-
return acc;
|
|
44
|
-
}, {});
|
|
45
|
-
localStorage.setItem(name, JSON.stringify(toStore));
|
|
46
|
-
}
|
|
47
|
-
return true;
|
|
19
|
+
const useStore = () => useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
20
|
+
const capName = name.capitalize();
|
|
21
|
+
const exposedState = {};
|
|
22
|
+
Object.keys(initialState).forEach(key => {
|
|
23
|
+
Object.defineProperty(exposedState, key, {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: () => state[key],
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
[name]: {
|
|
30
|
+
...exposedState,
|
|
31
|
+
setState,
|
|
32
|
+
resetState
|
|
48
33
|
},
|
|
49
|
-
|
|
50
|
-
};
|
|
51
|
-
|
|
34
|
+
[`use${capName}State`]: useStore
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -1,34 +1,39 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { objectPath } from "../helpers/index";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const interpolate = (str, data) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
import { createContext, useContext, useState, useEffect, } from "react";
|
|
4
|
+
const TranslationsContext = createContext(null);
|
|
5
|
+
const isBrowser = typeof window !== "undefined";
|
|
6
|
+
const interpolate = (str, data) => str.replace(/{{\s*(\w+)\s*}}/g, (_, key) => key in data ? String(data[key]) : `{{${key}}}`);
|
|
7
|
+
export const TranslationsProvider = ({ children, languages, }) => {
|
|
8
|
+
const [language, setLanguage] = useState(() => {
|
|
9
|
+
if (!isBrowser)
|
|
10
|
+
return "en";
|
|
11
|
+
return localStorage.getItem("language") ?? "en";
|
|
12
|
+
});
|
|
13
|
+
useEffect(() => { if (isBrowser) {
|
|
14
|
+
localStorage.setItem("language", language);
|
|
15
|
+
return () => { localStorage.removeItem("language"); };
|
|
16
|
+
} }, [language]);
|
|
17
|
+
return (_jsx(TranslationsContext.Provider, { value: { languages, changeLanguage: setLanguage, language }, children: children }));
|
|
12
18
|
};
|
|
13
|
-
export const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
catch (e) {
|
|
19
|
-
console.error(e);
|
|
20
|
-
return false;
|
|
19
|
+
export const useTranslations = () => {
|
|
20
|
+
const context = useContext(TranslationsContext);
|
|
21
|
+
if (!context) {
|
|
22
|
+
throw new Error("useTranslations must be used inside TranslationsProvider");
|
|
21
23
|
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
const { languages, language, changeLanguage } = context;
|
|
25
|
+
const translations = objectPath(languages[language]);
|
|
26
|
+
const translate = (key, data = {}) => {
|
|
27
|
+
if (!translations?.has?.(key))
|
|
28
|
+
return key;
|
|
29
|
+
const value = translations.get(key);
|
|
30
|
+
if (typeof value !== "string")
|
|
31
|
+
return String(value);
|
|
32
|
+
return Object.keys(data).length ? interpolate(value, data) : value;
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
translate,
|
|
36
|
+
changeLanguage,
|
|
37
|
+
language,
|
|
38
|
+
};
|
|
34
39
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gohanfromgoku/ui-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "ui-kit is a TypeScript based UI component library designed for building modern web applications with ease and efficiency.",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"scripts": {
|
|
@@ -26,12 +26,11 @@
|
|
|
26
26
|
"author": "GohanfromGoku",
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"
|
|
30
|
-
"preact": "^10.28.0"
|
|
29
|
+
"react": "^19.2.3"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
|
-
"@
|
|
34
|
-
"
|
|
32
|
+
"@types/react": "^19.2.8",
|
|
33
|
+
"react": "^19.2.3",
|
|
35
34
|
"tsc-alias": "^1.8.16",
|
|
36
35
|
"typescript": "^5.9.3"
|
|
37
36
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { ButtonHTMLAttributes } from "
|
|
2
|
-
import { type ReactNode
|
|
3
|
-
type ClickEvent = MouseEvent | TouchEvent
|
|
1
|
+
import type { ButtonHTMLAttributes, MouseEvent, TouchEvent } from "react";
|
|
2
|
+
import { type ReactNode } from "react";
|
|
3
|
+
type ClickEvent = MouseEvent<HTMLButtonElement> | TouchEvent<HTMLButtonElement>;
|
|
4
4
|
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
5
5
|
children: ReactNode;
|
|
6
6
|
className?: string;
|
|
@@ -8,7 +8,5 @@ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
|
8
8
|
onClick?: (event: ClickEvent) => void;
|
|
9
9
|
type?: "button" | "submit" | "reset";
|
|
10
10
|
}
|
|
11
|
-
declare const
|
|
12
|
-
|
|
13
|
-
}>;
|
|
14
|
-
export default _default;
|
|
11
|
+
declare const Button: import("react").NamedExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
12
|
+
export default Button;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ImgHTMLAttributes } from "
|
|
2
|
-
type ClickEvent = MouseEvent | TouchEvent
|
|
1
|
+
import type { ImgHTMLAttributes, MouseEvent, TouchEvent } from "react";
|
|
2
|
+
type ClickEvent = MouseEvent<HTMLImageElement> | TouchEvent<HTMLImageElement>;
|
|
3
3
|
export interface ImageProps extends ImgHTMLAttributes<HTMLImageElement> {
|
|
4
4
|
src: string;
|
|
5
5
|
className?: string;
|
|
@@ -8,7 +8,5 @@ export interface ImageProps extends ImgHTMLAttributes<HTMLImageElement> {
|
|
|
8
8
|
priority?: true | false;
|
|
9
9
|
onClick?: (event: ClickEvent) => void;
|
|
10
10
|
}
|
|
11
|
-
declare const
|
|
12
|
-
|
|
13
|
-
}>;
|
|
14
|
-
export default _default;
|
|
11
|
+
declare const Image: import("react").NamedExoticComponent<ImageProps & import("react").RefAttributes<HTMLImageElement>>;
|
|
12
|
+
export default Image;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ChangeEvent, InputHTMLAttributes } from "react";
|
|
2
2
|
interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "onChange"> {
|
|
3
3
|
placeholder?: string;
|
|
4
4
|
className?: string;
|
|
5
5
|
type?: string;
|
|
6
|
-
onChange?: (value: string, event:
|
|
6
|
+
onChange?: (value: string, event: ChangeEvent<HTMLInputElement>) => void;
|
|
7
7
|
name?: string;
|
|
8
8
|
}
|
|
9
|
-
declare const
|
|
10
|
-
export default
|
|
9
|
+
declare const Input: import("react").NamedExoticComponent<InputProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
10
|
+
export default Input;
|
|
@@ -6,7 +6,5 @@ interface TextProps {
|
|
|
6
6
|
tag?: any;
|
|
7
7
|
onClick?: (event: any) => void;
|
|
8
8
|
}
|
|
9
|
-
declare const
|
|
10
|
-
|
|
11
|
-
}>;
|
|
12
|
-
export default _default;
|
|
9
|
+
declare const Text: import("react").NamedExoticComponent<TextProps & import("react").RefAttributes<HTMLElement>>;
|
|
10
|
+
export default Text;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type ReactNode } from "
|
|
2
|
-
declare const
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
declare const Tooltip: import("react").MemoExoticComponent<({ message, children, className }: {
|
|
3
3
|
message: string;
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
className?: string;
|
|
6
|
-
}) => import("
|
|
7
|
-
export default
|
|
6
|
+
}) => import("react/jsx-runtime").JSX.Element>;
|
|
7
|
+
export default Tooltip;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
declare const useHandleClickOutside: (ref:
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
declare const useHandleClickOutside: (ref: RefObject<HTMLElement>, cb: () => void) => void;
|
|
3
3
|
export default useHandleClickOutside;
|
|
@@ -3,6 +3,13 @@ type SetQueryParams = (updates: Record<string, any>, options?: {
|
|
|
3
3
|
replace?: boolean;
|
|
4
4
|
pathname?: string;
|
|
5
5
|
}) => void;
|
|
6
|
-
declare const queryParamsSignal:
|
|
6
|
+
declare const queryParamsSignal: {
|
|
7
|
+
value: QueryParams;
|
|
8
|
+
} & {
|
|
9
|
+
setState: (partial: Partial<{
|
|
10
|
+
value: QueryParams;
|
|
11
|
+
}>) => void;
|
|
12
|
+
resetState: () => void;
|
|
13
|
+
};
|
|
7
14
|
export declare const setQueryParams: SetQueryParams;
|
|
8
15
|
export { queryParamsSignal as queryParams };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ComponentType } from "react";
|
|
2
|
+
interface Route {
|
|
3
|
+
pathname: string;
|
|
4
|
+
component: ComponentType;
|
|
5
|
+
}
|
|
6
|
+
declare const createBrowserRouter: (routes: Route[], { page404 }?: {
|
|
7
|
+
page404?: ComponentType;
|
|
8
|
+
}) => {
|
|
9
|
+
navigate: (to: string | number, { queryParams, replace }?: {
|
|
10
|
+
queryParams?: Record<string, any>;
|
|
11
|
+
replace?: boolean;
|
|
12
|
+
}) => void;
|
|
13
|
+
useLocationDetails: () => {
|
|
14
|
+
ancestorOrigins: DOMStringList;
|
|
15
|
+
hash: string;
|
|
16
|
+
host: string;
|
|
17
|
+
hostname: string;
|
|
18
|
+
href: string;
|
|
19
|
+
toString(): string;
|
|
20
|
+
origin: string;
|
|
21
|
+
pathname: string;
|
|
22
|
+
port: string;
|
|
23
|
+
protocol: string;
|
|
24
|
+
search: string;
|
|
25
|
+
assign(url: string | URL): void;
|
|
26
|
+
reload(): void;
|
|
27
|
+
replace(url: string | URL): void;
|
|
28
|
+
params: {};
|
|
29
|
+
queryParams: {};
|
|
30
|
+
};
|
|
31
|
+
Outlet: () => import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
};
|
|
33
|
+
export default createBrowserRouter;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type ComponentType } from "react";
|
|
2
|
+
interface Route {
|
|
3
|
+
pathname: string;
|
|
4
|
+
component: ComponentType;
|
|
5
|
+
}
|
|
6
|
+
declare const createMemoryRouter: (routes: Route[], { page404 }?: {
|
|
7
|
+
page404?: ComponentType;
|
|
8
|
+
}) => {
|
|
9
|
+
navigate: (to: string | number, { queryParams }?: {
|
|
10
|
+
queryParams?: Record<string, any>;
|
|
11
|
+
}) => void;
|
|
12
|
+
useLocationDetails: () => {
|
|
13
|
+
pathname: string;
|
|
14
|
+
ancestorOrigins: DOMStringList;
|
|
15
|
+
hash: string;
|
|
16
|
+
host: string;
|
|
17
|
+
hostname: string;
|
|
18
|
+
href: string;
|
|
19
|
+
toString(): string;
|
|
20
|
+
origin: string;
|
|
21
|
+
port: string;
|
|
22
|
+
protocol: string;
|
|
23
|
+
search: string;
|
|
24
|
+
assign(url: string | URL): void;
|
|
25
|
+
reload(): void;
|
|
26
|
+
replace(url: string | URL): void;
|
|
27
|
+
params: {};
|
|
28
|
+
queryParams: {};
|
|
29
|
+
} & {
|
|
30
|
+
setState: (partial: Partial<{
|
|
31
|
+
pathname: string;
|
|
32
|
+
ancestorOrigins: DOMStringList;
|
|
33
|
+
hash: string;
|
|
34
|
+
host: string;
|
|
35
|
+
hostname: string;
|
|
36
|
+
href: string;
|
|
37
|
+
toString(): string;
|
|
38
|
+
origin: string;
|
|
39
|
+
port: string;
|
|
40
|
+
protocol: string;
|
|
41
|
+
search: string;
|
|
42
|
+
assign(url: string | URL): void;
|
|
43
|
+
reload(): void;
|
|
44
|
+
replace(url: string | URL): void;
|
|
45
|
+
params: {};
|
|
46
|
+
queryParams: {};
|
|
47
|
+
}>) => void;
|
|
48
|
+
resetState: () => void;
|
|
49
|
+
};
|
|
50
|
+
Outlet: () => import("react/jsx-runtime").JSX.Element;
|
|
51
|
+
};
|
|
52
|
+
export default createMemoryRouter;
|
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
export { default as
|
|
2
|
-
export { default as
|
|
3
|
-
export { default as navigate } from "./navigate";
|
|
4
|
-
export { default as useLocationDetails } from "./useLocationDetails";
|
|
1
|
+
export { default as createBrowserRouter } from "./createBrowserRouter";
|
|
2
|
+
export { default as createMemoryRouter } from "./createMemoryRouter";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const copyToClipboard: (
|
|
1
|
+
declare const copyToClipboard: (this: string, message?: string) => Promise<true | undefined>;
|
|
2
2
|
export default copyToClipboard;
|
package/types/storage/index.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
setState: (
|
|
1
|
+
import "../prototypes";
|
|
2
|
+
export default function createStore<Name extends string, T extends Record<string, any>>(name: Name, initialState: T): { [K in Name]: T & {
|
|
3
|
+
setState: (partial: Partial<T>) => void;
|
|
4
4
|
resetState: () => void;
|
|
5
|
-
} & {
|
|
6
|
-
__signal: import("@preact/signals").Signal<T>;
|
|
7
|
-
};
|
|
8
|
-
export default createStore;
|
|
5
|
+
}; } & { [K in `use${Capitalize<Name>}State`]: () => T; };
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export declare const
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
type Languages = Record<string, Record<string, any>>;
|
|
3
|
+
export declare const TranslationsProvider: ({ children, languages, }: {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
languages: Languages;
|
|
6
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare const useTranslations: () => {
|
|
8
|
+
translate: (key: string, data?: Record<string, string | number>) => string;
|
|
9
|
+
changeLanguage: (lang: any) => void;
|
|
10
|
+
language: any;
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
-
import { activeRoute, location } from "./navigation.store";
|
|
3
|
-
import { Page404 } from "./Page404";
|
|
4
|
-
import { useEffect } from "preact/compat";
|
|
5
|
-
import isRouteMatching from "./isRouteMatching";
|
|
6
|
-
import { computed } from "@preact/signals";
|
|
7
|
-
import { extractParamsFromURL } from "./extractParamsFromURL";
|
|
8
|
-
import { extractQueryParamsFromURL } from "./extractQueryParamsFromURL";
|
|
9
|
-
const Outlet = ({ routes, page404: Page404Page = Page404 }) => {
|
|
10
|
-
const component = computed(() => activeRoute.value?.component ?? Page404Page);
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
const updateLocation = () => {
|
|
13
|
-
const active = routes.find(r => isRouteMatching(r.pathname)) || { pathname: window.location.href, component: Page404Page };
|
|
14
|
-
const { pathname: currentpath, href } = window.location;
|
|
15
|
-
const params = extractParamsFromURL(currentpath, active.pathname);
|
|
16
|
-
const queryParams = extractQueryParamsFromURL(href);
|
|
17
|
-
activeRoute.setState({ value: active });
|
|
18
|
-
location.setState({ value: { params, queryParams, ...window.location } });
|
|
19
|
-
};
|
|
20
|
-
updateLocation();
|
|
21
|
-
window.addEventListener("popstate", updateLocation);
|
|
22
|
-
return () => window.removeEventListener("popstate", updateLocation);
|
|
23
|
-
}, [routes]);
|
|
24
|
-
return _jsx(component.value, {});
|
|
25
|
-
};
|
|
26
|
-
export default Outlet;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { activeRoute, globalRoutes, location } from "./navigation.store";
|
|
2
|
-
import { extractParamsFromURL } from "./extractParamsFromURL";
|
|
3
|
-
import { extractQueryParamsFromURL } from "./extractQueryParamsFromURL";
|
|
4
|
-
import isRouteMatching from "./isRouteMatching";
|
|
5
|
-
import { Page404 } from "./Page404";
|
|
6
|
-
const createRoutes = (routes) => {
|
|
7
|
-
globalRoutes.setState({ value: routes });
|
|
8
|
-
const active = routes.find(r => isRouteMatching(r.pathname)) || { pathname: window.location.href, component: Page404 };
|
|
9
|
-
const { pathname: currentpath, href } = window.location;
|
|
10
|
-
const params = extractParamsFromURL(currentpath, active.pathname);
|
|
11
|
-
const queryParams = extractQueryParamsFromURL(href);
|
|
12
|
-
activeRoute.setState({ value: active });
|
|
13
|
-
location.setState({ value: { params, queryParams, ...window.location } });
|
|
14
|
-
return routes;
|
|
15
|
-
};
|
|
16
|
-
export default createRoutes;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @internal
|
|
3
|
-
*/
|
|
4
|
-
export const extractQueryParamsFromURL = (url) => {
|
|
5
|
-
const query = {};
|
|
6
|
-
const href = url.startsWith(window.location.origin) ? url.split(window.location.origin)[1] : url;
|
|
7
|
-
const parts = href.split("?");
|
|
8
|
-
if (parts.length > 2) {
|
|
9
|
-
throw "Invalid URL";
|
|
10
|
-
}
|
|
11
|
-
const search = parts[1];
|
|
12
|
-
if (search && search.length > 0) {
|
|
13
|
-
const searchSegments = search.split("&");
|
|
14
|
-
for (const ss of searchSegments) {
|
|
15
|
-
const ssparts = ss.split("=");
|
|
16
|
-
if (ssparts.length > 2) {
|
|
17
|
-
throw "Invalid URL";
|
|
18
|
-
}
|
|
19
|
-
const [key, value] = ssparts;
|
|
20
|
-
query[decodeURIComponent(key)] = decodeURIComponent(value ?? "");
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return query;
|
|
24
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @internal
|
|
3
|
-
*/
|
|
4
|
-
const isRouteMatching = (routePath) => {
|
|
5
|
-
const current = window.location.pathname;
|
|
6
|
-
if (routePath === "/" || routePath === "") {
|
|
7
|
-
return current === "/" || current === "/index.html" || current === "";
|
|
8
|
-
}
|
|
9
|
-
const routeParts = routePath.split("/").filter(Boolean);
|
|
10
|
-
const currentParts = current.split("/").filter(Boolean);
|
|
11
|
-
if (routeParts.length !== currentParts.length)
|
|
12
|
-
return false;
|
|
13
|
-
return routeParts.every((part, i) => part.startsWith(":") || part === currentParts[i]);
|
|
14
|
-
};
|
|
15
|
-
export default isRouteMatching;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { extractQueryParamsFromURL } from "./extractQueryParamsFromURL";
|
|
2
|
-
const createSearch = (queryParams) => {
|
|
3
|
-
const keys = Object.keys(queryParams);
|
|
4
|
-
if (keys.length > 0) {
|
|
5
|
-
let search = "?";
|
|
6
|
-
for (let index = 0; index < keys.length; index++) {
|
|
7
|
-
const key = keys[index];
|
|
8
|
-
search = `${search}${key}=${queryParams[key]}`;
|
|
9
|
-
if (index !== keys.length - 1) {
|
|
10
|
-
search = search + "&";
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
return search;
|
|
14
|
-
}
|
|
15
|
-
return "";
|
|
16
|
-
};
|
|
17
|
-
const generateURLFromParams = (pathname, queryParams) => {
|
|
18
|
-
const pathnameQueryParams = extractQueryParamsFromURL(pathname);
|
|
19
|
-
const allQueryParams = { ...pathnameQueryParams, ...queryParams };
|
|
20
|
-
const url = pathname.startsWith("/") ? `${window.location.origin}${pathname.split("?")[0]}` : `${window.location.origin}/${pathname.split("?")[0]}`;
|
|
21
|
-
const path = `${url}${createSearch(allQueryParams)}`;
|
|
22
|
-
return path;
|
|
23
|
-
};
|
|
24
|
-
const navigate = (path, { queryParams = {}, replace = false } = {}) => {
|
|
25
|
-
if (typeof path === "number") {
|
|
26
|
-
window.history.go(path);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
const pathname = generateURLFromParams(path, queryParams);
|
|
30
|
-
if (window.location.href === pathname) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
if (replace) {
|
|
34
|
-
window.history.replaceState({}, "", pathname);
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
window.history.pushState({}, "", pathname);
|
|
38
|
-
}
|
|
39
|
-
window.dispatchEvent(new Event("popstate"));
|
|
40
|
-
};
|
|
41
|
-
export default navigate;
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import createStore from "../storage/index";
|
|
2
|
-
export const location = createStore("location", { value: { params: {}, queryParams: {} } });
|
|
3
|
-
export const activeRoute = createStore("activeRoute", { value: {} });
|
|
4
|
-
export const globalRoutes = createStore("globalRoutes", { value: [] });
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { computed } from "@preact/signals";
|
|
2
|
-
import { globalRoutes, location } from "./navigation.store";
|
|
3
|
-
const useLocationDetails = () => {
|
|
4
|
-
if (globalRoutes.value.length === 0) {
|
|
5
|
-
throw "useLocationDetails cannot be used without initializing routes, use createRoutes initialize routes";
|
|
6
|
-
}
|
|
7
|
-
const values = computed(() => location.value);
|
|
8
|
-
return values.value;
|
|
9
|
-
};
|
|
10
|
-
export default useLocationDetails;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const Page404: () => import("preact").JSX.Element;
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { Route } from "./createRoutes";
|
|
2
|
-
export declare const location: {
|
|
3
|
-
value: {
|
|
4
|
-
params: {};
|
|
5
|
-
queryParams: {};
|
|
6
|
-
};
|
|
7
|
-
} & {
|
|
8
|
-
setState: (values: Partial<{
|
|
9
|
-
value: {
|
|
10
|
-
params: {};
|
|
11
|
-
queryParams: {};
|
|
12
|
-
};
|
|
13
|
-
}>) => void;
|
|
14
|
-
resetState: () => void;
|
|
15
|
-
} & {
|
|
16
|
-
__signal: import("@preact/signals").Signal<{
|
|
17
|
-
value: {
|
|
18
|
-
params: {};
|
|
19
|
-
queryParams: {};
|
|
20
|
-
};
|
|
21
|
-
}>;
|
|
22
|
-
};
|
|
23
|
-
export declare const activeRoute: {
|
|
24
|
-
value: Route;
|
|
25
|
-
} & {
|
|
26
|
-
setState: (values: Partial<{
|
|
27
|
-
value: Route;
|
|
28
|
-
}>) => void;
|
|
29
|
-
resetState: () => void;
|
|
30
|
-
} & {
|
|
31
|
-
__signal: import("@preact/signals").Signal<{
|
|
32
|
-
value: Route;
|
|
33
|
-
}>;
|
|
34
|
-
};
|
|
35
|
-
export declare const globalRoutes: {
|
|
36
|
-
value: Route[];
|
|
37
|
-
} & {
|
|
38
|
-
setState: (values: Partial<{
|
|
39
|
-
value: Route[];
|
|
40
|
-
}>) => void;
|
|
41
|
-
resetState: () => void;
|
|
42
|
-
} & {
|
|
43
|
-
__signal: import("@preact/signals").Signal<{
|
|
44
|
-
value: Route[];
|
|
45
|
-
}>;
|
|
46
|
-
};
|
|
File without changes
|