@geoinsight/react-components 0.1.1 → 0.2.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/cjs/index.css +17 -0
- package/dist/cjs/index.js +51 -0
- package/dist/esm/index.css +17 -0
- package/dist/esm/index.js +50 -2
- package/package.json +1 -1
- package/src/components/input/index.css +1 -0
- package/src/components/loading/index.css +8 -0
- package/src/components/loading/index.stories.tsx +20 -0
- package/src/components/loading/index.tsx +14 -0
- package/src/components/loading/index.types.ts +12 -0
- package/src/components/text-area/index.css +1 -0
- package/src/context/loading/index.stories.tsx +37 -0
- package/src/context/loading/index.tsx +111 -0
- package/src/context/themeContext.tsx +93 -0
- package/src/decorators/withColorScheme.tsx +20 -25
- package/src/decorators/withLoading.tsx +31 -0
- package/src/decorators/withWrapper.tsx +9 -0
- package/src/index.ts +2 -0
- package/src/stories/assets/loading.gif +0 -0
- package/src/stories/assets/spinner_2.png +0 -0
- package/src/styles/variables.css +15 -0
- package/src/types/palette-theme.d.ts +5 -0
- package/src/types/data-theme.d.ts +0 -5
package/dist/cjs/index.css
CHANGED
|
@@ -54,6 +54,9 @@
|
|
|
54
54
|
--color-neutral-100: var(--color-white);
|
|
55
55
|
--color-primary: var(--color-primary-500);
|
|
56
56
|
--color-secondary: var(--color-primary-600);
|
|
57
|
+
|
|
58
|
+
color: var(--color-neutral-100) !important;
|
|
59
|
+
background-color: var(--color-neutral-900) !important;
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
[data-theme="light"] {
|
|
@@ -61,6 +64,18 @@
|
|
|
61
64
|
--color-neutral-100: var(--color-black);
|
|
62
65
|
--color-primary: var(--color-primary-600);
|
|
63
66
|
--color-secondary: var(--color-primary-500);
|
|
67
|
+
color: var(--color-neutral-900) !important;
|
|
68
|
+
background-color: var(--color-neutral-100) !important;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@media (prefers-color-scheme: dark) {
|
|
72
|
+
html {
|
|
73
|
+
color-scheme: dark;
|
|
74
|
+
}
|
|
75
|
+
body {
|
|
76
|
+
color: var(--color-neutral-100);
|
|
77
|
+
background-color: var(--color-neutral-900);
|
|
78
|
+
}
|
|
64
79
|
}
|
|
65
80
|
|
|
66
81
|
[palette-theme="water"] {
|
|
@@ -186,6 +201,7 @@
|
|
|
186
201
|
}
|
|
187
202
|
|
|
188
203
|
.input {
|
|
204
|
+
background-color: var(--color-white);
|
|
189
205
|
border-radius: var(--spacing-8);
|
|
190
206
|
border: 2px solid var(--color-primary);
|
|
191
207
|
color: var(--color-black);
|
|
@@ -216,6 +232,7 @@
|
|
|
216
232
|
}
|
|
217
233
|
|
|
218
234
|
.textarea__input {
|
|
235
|
+
background-color: var(--color-white);
|
|
219
236
|
box-sizing: border-box;
|
|
220
237
|
border-radius: var(--spacing-8);
|
|
221
238
|
border: 2px solid var(--color-primary);
|
package/dist/cjs/index.js
CHANGED
|
@@ -32,6 +32,57 @@ function TextArea({ className = "", disabled = true, hasToggleButton = true, hid
|
|
|
32
32
|
}, placeholder: placeholder, disabled: disabled, ...rest }), hasToggleButton && (jsxRuntime.jsx("button", { className: clsx("textarea__button", isShow && "textarea__button--show"), onClick: handleClickToggle, disabled: disabled, children: jsxRuntime.jsx(tb.TbArrowsDiagonal2, { size: "1.5rem" }) }))] }));
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
const ThemeContext = react.createContext(undefined);
|
|
36
|
+
function ThemeProvider({ children }) {
|
|
37
|
+
const [dataTheme, setDataTheme] = react.useState();
|
|
38
|
+
const [paletteTheme, setPaletteTheme] = react.useState();
|
|
39
|
+
react.useEffect(() => {
|
|
40
|
+
if (window.matchMedia) {
|
|
41
|
+
if (localStorage.getItem("data-theme")) {
|
|
42
|
+
document.documentElement.setAttribute("data-theme", localStorage.getItem("data-theme"));
|
|
43
|
+
setDataTheme(localStorage.getItem("data-theme"));
|
|
44
|
+
}
|
|
45
|
+
else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
46
|
+
document.documentElement.setAttribute("data-theme", "dark");
|
|
47
|
+
setDataTheme("dark");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}, []);
|
|
51
|
+
const switchDataTheme = (mode) => {
|
|
52
|
+
document.documentElement.setAttribute("data-theme", mode);
|
|
53
|
+
setDataTheme(mode);
|
|
54
|
+
localStorage.setItem("data-theme", mode);
|
|
55
|
+
};
|
|
56
|
+
const switchPaletteTheme = (mode) => {
|
|
57
|
+
document.documentElement.setAttribute("palette-theme", mode);
|
|
58
|
+
setPaletteTheme(mode);
|
|
59
|
+
localStorage.setItem("palette-theme", mode);
|
|
60
|
+
};
|
|
61
|
+
return (jsxRuntime.jsx(ThemeContext.Provider, { value: { dataTheme, switchDataTheme, paletteTheme, switchPaletteTheme }, children: children }));
|
|
62
|
+
}
|
|
63
|
+
function useTheme({ dataTheme = undefined, paletteTheme = "water", } = {}) {
|
|
64
|
+
const context = react.useContext(ThemeContext);
|
|
65
|
+
// only happens if there is an initial mode value.
|
|
66
|
+
react.useEffect(() => {
|
|
67
|
+
if (dataTheme && !localStorage.getItem("data-theme")) {
|
|
68
|
+
context?.switchDataTheme(dataTheme);
|
|
69
|
+
}
|
|
70
|
+
else if (!dataTheme && localStorage.getItem("data-theme")) {
|
|
71
|
+
localStorage.removeItem("data-theme");
|
|
72
|
+
}
|
|
73
|
+
}, []);
|
|
74
|
+
react.useEffect(() => {
|
|
75
|
+
context?.switchPaletteTheme(paletteTheme);
|
|
76
|
+
}, []);
|
|
77
|
+
if (context === undefined) {
|
|
78
|
+
throw new Error("useTheme must be used within a ThemeProvider");
|
|
79
|
+
}
|
|
80
|
+
return context;
|
|
81
|
+
}
|
|
82
|
+
|
|
35
83
|
exports.Button = Button;
|
|
36
84
|
exports.Input = Input;
|
|
37
85
|
exports.TextArea = TextArea;
|
|
86
|
+
exports.ThemeContext = ThemeContext;
|
|
87
|
+
exports.ThemeProvider = ThemeProvider;
|
|
88
|
+
exports.useTheme = useTheme;
|
package/dist/esm/index.css
CHANGED
|
@@ -54,6 +54,9 @@
|
|
|
54
54
|
--color-neutral-100: var(--color-white);
|
|
55
55
|
--color-primary: var(--color-primary-500);
|
|
56
56
|
--color-secondary: var(--color-primary-600);
|
|
57
|
+
|
|
58
|
+
color: var(--color-neutral-100) !important;
|
|
59
|
+
background-color: var(--color-neutral-900) !important;
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
[data-theme="light"] {
|
|
@@ -61,6 +64,18 @@
|
|
|
61
64
|
--color-neutral-100: var(--color-black);
|
|
62
65
|
--color-primary: var(--color-primary-600);
|
|
63
66
|
--color-secondary: var(--color-primary-500);
|
|
67
|
+
color: var(--color-neutral-900) !important;
|
|
68
|
+
background-color: var(--color-neutral-100) !important;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@media (prefers-color-scheme: dark) {
|
|
72
|
+
html {
|
|
73
|
+
color-scheme: dark;
|
|
74
|
+
}
|
|
75
|
+
body {
|
|
76
|
+
color: var(--color-neutral-100);
|
|
77
|
+
background-color: var(--color-neutral-900);
|
|
78
|
+
}
|
|
64
79
|
}
|
|
65
80
|
|
|
66
81
|
[palette-theme="water"] {
|
|
@@ -186,6 +201,7 @@
|
|
|
186
201
|
}
|
|
187
202
|
|
|
188
203
|
.input {
|
|
204
|
+
background-color: var(--color-white);
|
|
189
205
|
border-radius: var(--spacing-8);
|
|
190
206
|
border: 2px solid var(--color-primary);
|
|
191
207
|
color: var(--color-black);
|
|
@@ -216,6 +232,7 @@
|
|
|
216
232
|
}
|
|
217
233
|
|
|
218
234
|
.textarea__input {
|
|
235
|
+
background-color: var(--color-white);
|
|
219
236
|
box-sizing: border-box;
|
|
220
237
|
border-radius: var(--spacing-8);
|
|
221
238
|
border: 2px solid var(--color-primary);
|
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
|
-
import { useRef, useState } from 'react';
|
|
3
|
+
import { useRef, useState, createContext, useEffect, useContext } from 'react';
|
|
4
4
|
import { TbArrowsDiagonal2 } from 'react-icons/tb';
|
|
5
5
|
|
|
6
6
|
function Button({ children = "Click me", className = "", icon = undefined, isNewWindow = false, mode = "primary", size = "medium", as = "button", ...rest }) {
|
|
@@ -30,4 +30,52 @@ function TextArea({ className = "", disabled = true, hasToggleButton = true, hid
|
|
|
30
30
|
}, placeholder: placeholder, disabled: disabled, ...rest }), hasToggleButton && (jsx("button", { className: clsx("textarea__button", isShow && "textarea__button--show"), onClick: handleClickToggle, disabled: disabled, children: jsx(TbArrowsDiagonal2, { size: "1.5rem" }) }))] }));
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
const ThemeContext = createContext(undefined);
|
|
34
|
+
function ThemeProvider({ children }) {
|
|
35
|
+
const [dataTheme, setDataTheme] = useState();
|
|
36
|
+
const [paletteTheme, setPaletteTheme] = useState();
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (window.matchMedia) {
|
|
39
|
+
if (localStorage.getItem("data-theme")) {
|
|
40
|
+
document.documentElement.setAttribute("data-theme", localStorage.getItem("data-theme"));
|
|
41
|
+
setDataTheme(localStorage.getItem("data-theme"));
|
|
42
|
+
}
|
|
43
|
+
else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
44
|
+
document.documentElement.setAttribute("data-theme", "dark");
|
|
45
|
+
setDataTheme("dark");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}, []);
|
|
49
|
+
const switchDataTheme = (mode) => {
|
|
50
|
+
document.documentElement.setAttribute("data-theme", mode);
|
|
51
|
+
setDataTheme(mode);
|
|
52
|
+
localStorage.setItem("data-theme", mode);
|
|
53
|
+
};
|
|
54
|
+
const switchPaletteTheme = (mode) => {
|
|
55
|
+
document.documentElement.setAttribute("palette-theme", mode);
|
|
56
|
+
setPaletteTheme(mode);
|
|
57
|
+
localStorage.setItem("palette-theme", mode);
|
|
58
|
+
};
|
|
59
|
+
return (jsx(ThemeContext.Provider, { value: { dataTheme, switchDataTheme, paletteTheme, switchPaletteTheme }, children: children }));
|
|
60
|
+
}
|
|
61
|
+
function useTheme({ dataTheme = undefined, paletteTheme = "water", } = {}) {
|
|
62
|
+
const context = useContext(ThemeContext);
|
|
63
|
+
// only happens if there is an initial mode value.
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (dataTheme && !localStorage.getItem("data-theme")) {
|
|
66
|
+
context?.switchDataTheme(dataTheme);
|
|
67
|
+
}
|
|
68
|
+
else if (!dataTheme && localStorage.getItem("data-theme")) {
|
|
69
|
+
localStorage.removeItem("data-theme");
|
|
70
|
+
}
|
|
71
|
+
}, []);
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
context?.switchPaletteTheme(paletteTheme);
|
|
74
|
+
}, []);
|
|
75
|
+
if (context === undefined) {
|
|
76
|
+
throw new Error("useTheme must be used within a ThemeProvider");
|
|
77
|
+
}
|
|
78
|
+
return context;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { Button, Input, TextArea, ThemeContext, ThemeProvider, useTheme };
|
package/package.json
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
|
|
3
|
+
import { Loading } from "./index";
|
|
4
|
+
import { withColorScheme } from "../../decorators/withColorScheme";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Loading> = {
|
|
7
|
+
title: "Example/Loading",
|
|
8
|
+
component: Loading,
|
|
9
|
+
decorators: [withColorScheme]
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default meta;
|
|
13
|
+
|
|
14
|
+
type Story = StoryObj<typeof Loading>;
|
|
15
|
+
|
|
16
|
+
export const Primary: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
img: ""
|
|
19
|
+
},
|
|
20
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Loading as LoadingProps } from "./index.types";
|
|
2
|
+
import "./index.css";
|
|
3
|
+
import loading from "../../stories/assets/loading.gif";
|
|
4
|
+
|
|
5
|
+
export function Loading({ img, children }: LoadingProps) {
|
|
6
|
+
return (
|
|
7
|
+
<div className="loading">
|
|
8
|
+
<img src={img ? img : loading} />
|
|
9
|
+
{children}
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default Loading;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
|
|
3
|
+
import { LoadingProvider } from ".";
|
|
4
|
+
import { withColorScheme } from "../../decorators/withColorScheme";
|
|
5
|
+
import { withLoading } from "../../decorators/withLoading";
|
|
6
|
+
import spinner from "../../stories/assets/spinner_2.png";
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof LoadingProvider> = {
|
|
9
|
+
title: "Context/Loading",
|
|
10
|
+
component: () => <div></div>,
|
|
11
|
+
decorators: [withColorScheme, withLoading],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
|
|
16
|
+
type Story = StoryObj<typeof LoadingProvider>;
|
|
17
|
+
|
|
18
|
+
export const Basic: Story = {};
|
|
19
|
+
|
|
20
|
+
export const CustomMessage: Story = {
|
|
21
|
+
parameters: {
|
|
22
|
+
loadingOptions: {
|
|
23
|
+
message: "Updating form",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const CustomImage: Story = {
|
|
29
|
+
parameters: {
|
|
30
|
+
loadingOptions: {
|
|
31
|
+
isRef: true,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
args: {
|
|
35
|
+
img: spinner,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
ReactNode,
|
|
3
|
+
RefObject,
|
|
4
|
+
createContext,
|
|
5
|
+
useContext,
|
|
6
|
+
useEffect,
|
|
7
|
+
useReducer,
|
|
8
|
+
} from "react";
|
|
9
|
+
import Loading from "../../components/loading";
|
|
10
|
+
|
|
11
|
+
type Action = {
|
|
12
|
+
type: "set_ref" | "start_loading" | "stop_loading" | "set_message";
|
|
13
|
+
ref?: RefObject<ReactNode>;
|
|
14
|
+
message?: string;
|
|
15
|
+
};
|
|
16
|
+
type State = {
|
|
17
|
+
isLoading: boolean;
|
|
18
|
+
message?: string | React.ReactNode;
|
|
19
|
+
ref?: RefObject<ReactNode>;
|
|
20
|
+
};
|
|
21
|
+
type Context = {
|
|
22
|
+
state: State;
|
|
23
|
+
setRef: (ref: RefObject<ReactNode>) => void;
|
|
24
|
+
setMessage: (message: string) => void;
|
|
25
|
+
startLoading: () => void;
|
|
26
|
+
stopLoading: () => void;
|
|
27
|
+
};
|
|
28
|
+
type LoadingProviderProps = { children: React.ReactNode };
|
|
29
|
+
type UseLoadingProps = {
|
|
30
|
+
ref?: RefObject<ReactNode>;
|
|
31
|
+
message?: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const LoadingContext = createContext<Context | undefined>(undefined);
|
|
35
|
+
|
|
36
|
+
function loadingReducer(state: State, action: Action) {
|
|
37
|
+
switch (action.type) {
|
|
38
|
+
case "set_ref": {
|
|
39
|
+
return { ...state, ref: action.ref };
|
|
40
|
+
}
|
|
41
|
+
case "start_loading": {
|
|
42
|
+
return { ...state, isLoading: true };
|
|
43
|
+
}
|
|
44
|
+
case "stop_loading": {
|
|
45
|
+
return { ...state, isLoading: false };
|
|
46
|
+
}
|
|
47
|
+
case "set_message": {
|
|
48
|
+
return { ...state, message: action.message };
|
|
49
|
+
}
|
|
50
|
+
default: {
|
|
51
|
+
throw new Error(`Unhandled action type: ${action.type}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function LoadingProvider({ children }: LoadingProviderProps) {
|
|
57
|
+
const [{ isLoading, message, ref }, dispatch] = useReducer(loadingReducer, {
|
|
58
|
+
isLoading: false,
|
|
59
|
+
message: "Loading",
|
|
60
|
+
ref: undefined,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const setRef = (ref: RefObject<ReactNode>) => {
|
|
64
|
+
dispatch({ type: "set_ref", ref });
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const setMessage = (message: string) => {
|
|
68
|
+
dispatch({ type: "set_message", message });
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const startLoading = () => {
|
|
72
|
+
dispatch({ type: "start_loading" });
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const stopLoading = () => {
|
|
76
|
+
dispatch({ type: "stop_loading" });
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<LoadingContext.Provider
|
|
81
|
+
value={{
|
|
82
|
+
state: { ref, message, isLoading },
|
|
83
|
+
setMessage,
|
|
84
|
+
setRef,
|
|
85
|
+
startLoading,
|
|
86
|
+
stopLoading,
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
{!ref && <Loading>{message}</Loading>}
|
|
90
|
+
{children}
|
|
91
|
+
</LoadingContext.Provider>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function useLoading({ ref, message }: UseLoadingProps = {}) {
|
|
96
|
+
const context = useContext(LoadingContext);
|
|
97
|
+
|
|
98
|
+
// only happens if there is an initial mode value.
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
ref && context?.setRef(ref);
|
|
101
|
+
message && context?.setMessage(message);
|
|
102
|
+
}, []);
|
|
103
|
+
|
|
104
|
+
if (context === undefined) {
|
|
105
|
+
throw new Error("useLoading must be used within a LoadingProvider");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return context;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { LoadingContext, LoadingProvider, useLoading };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { PaletteTheme } from "palette-theme";
|
|
2
|
+
import React, {
|
|
3
|
+
Dispatch,
|
|
4
|
+
SetStateAction,
|
|
5
|
+
createContext,
|
|
6
|
+
useContext,
|
|
7
|
+
useEffect,
|
|
8
|
+
useState,
|
|
9
|
+
} from "react";
|
|
10
|
+
|
|
11
|
+
type DataTheme = "light" | "dark";
|
|
12
|
+
|
|
13
|
+
type State = {
|
|
14
|
+
dataTheme?: DataTheme;
|
|
15
|
+
switchDataTheme: (mode: DataTheme) => void;
|
|
16
|
+
paletteTheme?: PaletteTheme;
|
|
17
|
+
switchPaletteTheme: (mode: PaletteTheme) => void;
|
|
18
|
+
};
|
|
19
|
+
type ThemeProviderProps = { children: React.ReactNode };
|
|
20
|
+
type UseThemeProps = {
|
|
21
|
+
dataTheme?: DataTheme;
|
|
22
|
+
paletteTheme?: PaletteTheme;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const ThemeContext = createContext<State | undefined>(undefined);
|
|
26
|
+
|
|
27
|
+
function ThemeProvider({ children }: ThemeProviderProps) {
|
|
28
|
+
const [dataTheme, setDataTheme] = useState<DataTheme>();
|
|
29
|
+
const [paletteTheme, setPaletteTheme] = useState<PaletteTheme>();
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (window.matchMedia) {
|
|
33
|
+
if (localStorage.getItem("data-theme")) {
|
|
34
|
+
document.documentElement.setAttribute(
|
|
35
|
+
"data-theme",
|
|
36
|
+
localStorage.getItem("data-theme") as string
|
|
37
|
+
);
|
|
38
|
+
setDataTheme(localStorage.getItem("data-theme") as DataTheme);
|
|
39
|
+
} else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
40
|
+
document.documentElement.setAttribute("data-theme", "dark");
|
|
41
|
+
setDataTheme("dark");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}, []);
|
|
45
|
+
|
|
46
|
+
const switchDataTheme = (mode: DataTheme) => {
|
|
47
|
+
document.documentElement.setAttribute("data-theme", mode);
|
|
48
|
+
setDataTheme(mode);
|
|
49
|
+
localStorage.setItem("data-theme", mode);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const switchPaletteTheme = (mode: PaletteTheme) => {
|
|
53
|
+
document.documentElement.setAttribute("palette-theme", mode);
|
|
54
|
+
setPaletteTheme(mode);
|
|
55
|
+
localStorage.setItem("palette-theme", mode);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<ThemeContext.Provider
|
|
60
|
+
value={{ dataTheme, switchDataTheme, paletteTheme, switchPaletteTheme }}
|
|
61
|
+
>
|
|
62
|
+
{children}
|
|
63
|
+
</ThemeContext.Provider>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function useTheme({
|
|
68
|
+
dataTheme = undefined,
|
|
69
|
+
paletteTheme = "water",
|
|
70
|
+
}: UseThemeProps = {}) {
|
|
71
|
+
const context = useContext(ThemeContext);
|
|
72
|
+
|
|
73
|
+
// only happens if there is an initial mode value.
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (dataTheme && !localStorage.getItem("data-theme")) {
|
|
76
|
+
context?.switchDataTheme(dataTheme);
|
|
77
|
+
} else if (!dataTheme && localStorage.getItem("data-theme")) {
|
|
78
|
+
localStorage.removeItem("data-theme");
|
|
79
|
+
}
|
|
80
|
+
}, []);
|
|
81
|
+
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
context?.switchPaletteTheme(paletteTheme);
|
|
84
|
+
}, []);
|
|
85
|
+
|
|
86
|
+
if (context === undefined) {
|
|
87
|
+
throw new Error("useTheme must be used within a ThemeProvider");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return context;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export { ThemeContext, ThemeProvider, useTheme };
|
|
@@ -1,34 +1,29 @@
|
|
|
1
1
|
import { StoryContext, StoryFn } from "@storybook/react";
|
|
2
|
+
import { ThemeProvider, useTheme } from "../context/themeContext";
|
|
3
|
+
import "../styles/variables.css";
|
|
4
|
+
import { useEffect } from "react";
|
|
2
5
|
|
|
3
6
|
export const withColorScheme = (Story: StoryFn, context: StoryContext) => {
|
|
7
|
+
return (
|
|
8
|
+
<ThemeProvider>
|
|
9
|
+
<Wrapped Story={Story} context={context} />
|
|
10
|
+
</ThemeProvider>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const Wrapped = ({ Story, context } : { Story: StoryFn, context: StoryContext}) => {
|
|
4
15
|
const { theme, palette } = context.globals;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}}
|
|
15
|
-
>
|
|
16
|
-
<Story />
|
|
17
|
-
</div>
|
|
18
|
-
);
|
|
19
|
-
}
|
|
16
|
+
const switchTheme = useTheme();
|
|
17
|
+
|
|
18
|
+
useEffect (()=> {
|
|
19
|
+
switchTheme.switchDataTheme(theme)
|
|
20
|
+
}, [theme]);
|
|
21
|
+
|
|
22
|
+
useEffect (()=> {
|
|
23
|
+
switchTheme.switchPaletteTheme(palette)
|
|
24
|
+
}, [palette]);
|
|
20
25
|
|
|
21
26
|
return (
|
|
22
|
-
<div
|
|
23
|
-
data-theme="dark"
|
|
24
|
-
palette-theme={palette}
|
|
25
|
-
style={{
|
|
26
|
-
background: "var(--color-black)",
|
|
27
|
-
height: "150px",
|
|
28
|
-
padding: "16px",
|
|
29
|
-
}}
|
|
30
|
-
>
|
|
31
27
|
<Story />
|
|
32
|
-
</div>
|
|
33
28
|
);
|
|
34
29
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useRef } from "react";
|
|
2
|
+
import { StoryContext, StoryFn } from "@storybook/react";
|
|
3
|
+
import { LoadingProvider, useLoading } from "../context/loading";
|
|
4
|
+
|
|
5
|
+
const LoadingProviderMock = ({ Story, loadingOptions, loadingArgs }) => {
|
|
6
|
+
const ref = useRef();
|
|
7
|
+
const loading = useLoading({
|
|
8
|
+
...(loadingOptions?.isRef && { ref: ref }),
|
|
9
|
+
...(loadingOptions?.message && { message: loadingOptions.message }),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
// initialize stuff here
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
{loading.state.ref && <img ref={ref} src={loadingArgs.img} />}
|
|
16
|
+
<Story />
|
|
17
|
+
</>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const withLoading = (Story: StoryFn, context: StoryContext) => {
|
|
22
|
+
return (
|
|
23
|
+
<LoadingProvider>
|
|
24
|
+
<LoadingProviderMock
|
|
25
|
+
Story={Story}
|
|
26
|
+
loadingOptions={context.parameters.loadingOptions}
|
|
27
|
+
loadingArgs={context.args}
|
|
28
|
+
/>
|
|
29
|
+
</LoadingProvider>
|
|
30
|
+
);
|
|
31
|
+
};
|
package/src/index.ts
CHANGED
|
Binary file
|
|
Binary file
|
package/src/styles/variables.css
CHANGED
|
@@ -54,6 +54,9 @@
|
|
|
54
54
|
--color-neutral-100: var(--color-white);
|
|
55
55
|
--color-primary: var(--color-primary-500);
|
|
56
56
|
--color-secondary: var(--color-primary-600);
|
|
57
|
+
|
|
58
|
+
color: var(--color-neutral-100) !important;
|
|
59
|
+
background-color: var(--color-neutral-900) !important;
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
[data-theme="light"] {
|
|
@@ -61,6 +64,18 @@
|
|
|
61
64
|
--color-neutral-100: var(--color-black);
|
|
62
65
|
--color-primary: var(--color-primary-600);
|
|
63
66
|
--color-secondary: var(--color-primary-500);
|
|
67
|
+
color: var(--color-neutral-900) !important;
|
|
68
|
+
background-color: var(--color-neutral-100) !important;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@media (prefers-color-scheme: dark) {
|
|
72
|
+
html {
|
|
73
|
+
color-scheme: dark;
|
|
74
|
+
}
|
|
75
|
+
body {
|
|
76
|
+
color: var(--color-neutral-100);
|
|
77
|
+
background-color: var(--color-neutral-900);
|
|
78
|
+
}
|
|
64
79
|
}
|
|
65
80
|
|
|
66
81
|
[palette-theme="water"] {
|