@geoinsight/react-components 0.3.1 → 0.3.3

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.
@@ -281,3 +281,57 @@
281
281
  background: var(--color-primary-700);
282
282
  color: var(--color-neutral-100);
283
283
  }
284
+
285
+ .modal {
286
+ color: var(--color-neutral-900);
287
+ }
288
+
289
+ .modal__overlay {
290
+ background: rgba(0, 0, 0, 0.3);
291
+ bottom: 0;
292
+ left: 0;
293
+ position: fixed;
294
+ right: 0;
295
+ top: 0;
296
+ }
297
+
298
+ .modal__body {
299
+ background: white;
300
+ border-radius: var(--spacing-8);
301
+ border: 1px solid var(--color-neutral-600);
302
+ left: 50%;
303
+ padding: var(--spacing-4) var(--spacing-4);
304
+ position: absolute;
305
+ right: var(--spacing-16);
306
+ top: 50%;
307
+ transform: translate(-50%, -50%);
308
+ z-index: 5;
309
+ }
310
+
311
+ .modal__close {
312
+ position: absolute;
313
+ right: calc(var(--spacing-16) * -1);
314
+ top: calc(var(--spacing-16) * -1);
315
+ z-index: 5;
316
+ }
317
+
318
+ .modal__content {
319
+ border: 1px solid var(--color-neutral-100);
320
+ border-radius: var(--spacing-8);
321
+ display: flex;
322
+ flex-direction: column;
323
+ gap: var(--spacing-16);
324
+ padding: 0 var(--spacing-16);
325
+ }
326
+
327
+ .modal__footer {
328
+ padding-bottom: var(--spacing-16);
329
+ }
330
+ .loading {
331
+ align-items: center;
332
+ display: flex;
333
+ flex-direction: column;
334
+ height: 100%;
335
+ justify-content: center;;
336
+ position: relative;
337
+ }
package/dist/cjs/index.js CHANGED
@@ -4,6 +4,7 @@ var jsxRuntime = require('react/jsx-runtime');
4
4
  var clsx = require('clsx');
5
5
  var react = require('react');
6
6
  var tb = require('react-icons/tb');
7
+ var io5 = require('react-icons/io5');
7
8
 
8
9
  const Anchor = ({ Custom, children, ...rest }) => Custom ? jsxRuntime.jsx(Custom, { ...rest, children: children }) : jsxRuntime.jsx("a", { ...rest, children: children });
9
10
  function Button({ children = "Click me", className = "", icon = undefined, isNewWindow = false, mode = "primary", size = "medium", as = "button", CustomAnchor, ...rest }) {
@@ -33,6 +34,14 @@ function TextArea({ className = "", disabled = true, hasToggleButton = true, hid
33
34
  }, 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" }) }))] }));
34
35
  }
35
36
 
37
+ function Modal({ modalref, children, title, subtitle, footer, hasCloseButton = true, handleClose, }) {
38
+ return (jsxRuntime.jsxs("div", { className: "modal", children: [jsxRuntime.jsx("div", { className: "modal__overlay" }), jsxRuntime.jsxs("div", { ref: modalref, className: "modal__body", children: [hasCloseButton && (jsxRuntime.jsx(Button, { mode: "secondary", className: "modal__close", size: "small", onClick: handleClose, children: jsxRuntime.jsx(io5.IoClose, {}) })), jsxRuntime.jsxs("div", { className: "modal__content", children: [title && (jsxRuntime.jsxs("div", { className: "modal__header", children: [jsxRuntime.jsx("h3", { children: title }), jsxRuntime.jsx("h6", { children: subtitle })] })), jsxRuntime.jsx("div", { className: "modal__children", children: children }), footer && jsxRuntime.jsx("div", { className: "modal__footer", children: footer })] })] })] }));
39
+ }
40
+
41
+ function Loading({ img, children }) {
42
+ return (jsxRuntime.jsxs("div", { className: "loading", children: [jsxRuntime.jsx("img", { src: img ? img : "../../stories/assets/loading.gif" }), children] }));
43
+ }
44
+
36
45
  const ThemeContext = react.createContext(undefined);
37
46
  function ThemeProvider({ children }) {
38
47
  const [dataTheme, setDataTheme] = react.useState();
@@ -81,9 +90,138 @@ function useTheme({ dataTheme = undefined, paletteTheme = "water", } = {}) {
81
90
  return context;
82
91
  }
83
92
 
93
+ const LoadingContext = react.createContext(undefined);
94
+ function loadingReducer(state, action) {
95
+ switch (action.type) {
96
+ case "set_ref": {
97
+ return { ...state, ref: action.ref };
98
+ }
99
+ case "start_loading": {
100
+ return { ...state, isLoading: true };
101
+ }
102
+ case "stop_loading": {
103
+ return { ...state, isLoading: false };
104
+ }
105
+ case "set_message": {
106
+ return { ...state, message: action.message };
107
+ }
108
+ default: {
109
+ throw new Error(`Unhandled action type: ${action.type}`);
110
+ }
111
+ }
112
+ }
113
+ function LoadingProvider({ children }) {
114
+ const [{ isLoading, message, ref }, dispatch] = react.useReducer(loadingReducer, {
115
+ isLoading: false,
116
+ message: "Loading",
117
+ ref: undefined,
118
+ });
119
+ const setRef = (ref) => {
120
+ dispatch({ type: "set_ref", ref });
121
+ };
122
+ const setMessage = (message) => {
123
+ dispatch({ type: "set_message", message });
124
+ };
125
+ const startLoading = () => {
126
+ dispatch({ type: "start_loading" });
127
+ };
128
+ const stopLoading = () => {
129
+ dispatch({ type: "stop_loading" });
130
+ };
131
+ return (jsxRuntime.jsxs(LoadingContext.Provider, { value: {
132
+ state: { ref, message, isLoading },
133
+ setMessage,
134
+ setRef,
135
+ startLoading,
136
+ stopLoading,
137
+ }, children: [!ref && jsxRuntime.jsx(Loading, { children: message }), children] }));
138
+ }
139
+ function useLoading({ ref, message } = {}) {
140
+ const context = react.useContext(LoadingContext);
141
+ // only happens if there is an initial mode value.
142
+ react.useEffect(() => {
143
+ ref && context?.setRef(ref);
144
+ message && context?.setMessage(message);
145
+ }, []);
146
+ if (context === undefined) {
147
+ throw new Error("useLoading must be used within a LoadingProvider");
148
+ }
149
+ return context;
150
+ }
151
+
152
+ const ModalContext = react.createContext(undefined);
153
+ function modalReducer(state, action) {
154
+ switch (action.type) {
155
+ case "open_modal": {
156
+ return { ...state, ...action.modal, isModal: true };
157
+ }
158
+ case "close_modal": {
159
+ return { ...state, isModal: false };
160
+ }
161
+ default: {
162
+ throw new Error(`Unhandled action type: ${action.type}`);
163
+ }
164
+ }
165
+ }
166
+ const defaultState = {
167
+ subtitle: undefined,
168
+ title: undefined,
169
+ content: undefined,
170
+ hasCloseButton: true,
171
+ footer: undefined,
172
+ };
173
+ function ModalProvider({ children }) {
174
+ const ref = react.useRef(null);
175
+ const [state, dispatch] = react.useReducer(modalReducer, {
176
+ isModal: false,
177
+ ...defaultState,
178
+ });
179
+ const openModal = (modal) => {
180
+ dispatch({ type: "open_modal", modal });
181
+ };
182
+ const closeModal = () => {
183
+ dispatch({ type: "close_modal" });
184
+ };
185
+ react.useEffect(() => {
186
+ if (state.isModal) {
187
+ const listener = (e) => {
188
+ if (state.isModal &&
189
+ ref.current &&
190
+ !ref.current.contains(e.target)) {
191
+ closeModal();
192
+ }
193
+ };
194
+ document.addEventListener("mousedown", listener);
195
+ return () => {
196
+ document.removeEventListener("mousedown", listener);
197
+ };
198
+ }
199
+ }, [closeModal]);
200
+ return (jsxRuntime.jsxs(ModalContext.Provider, { value: {
201
+ state,
202
+ openModal,
203
+ closeModal,
204
+ }, children: [children, state.isModal && (jsxRuntime.jsx(Modal, { modalref: ref, title: state.title, footer: state.footer, handleClose: closeModal, subtitle: state.subtitle, children: state.content }))] }));
205
+ }
206
+ function useModal({} = {}) {
207
+ const context = react.useContext(ModalContext);
208
+ if (context === undefined) {
209
+ throw new Error("useModal must be used within a ModalProvider");
210
+ }
211
+ return context;
212
+ }
213
+
84
214
  exports.Button = Button;
85
215
  exports.Input = Input;
216
+ exports.Loading = Loading;
217
+ exports.LoadingContext = LoadingContext;
218
+ exports.LoadingProvider = LoadingProvider;
219
+ exports.Modal = Modal;
220
+ exports.ModalContext = ModalContext;
221
+ exports.ModalProvider = ModalProvider;
86
222
  exports.TextArea = TextArea;
87
223
  exports.ThemeContext = ThemeContext;
88
224
  exports.ThemeProvider = ThemeProvider;
225
+ exports.useLoading = useLoading;
226
+ exports.useModal = useModal;
89
227
  exports.useTheme = useTheme;
@@ -281,3 +281,57 @@
281
281
  background: var(--color-primary-700);
282
282
  color: var(--color-neutral-100);
283
283
  }
284
+
285
+ .modal {
286
+ color: var(--color-neutral-900);
287
+ }
288
+
289
+ .modal__overlay {
290
+ background: rgba(0, 0, 0, 0.3);
291
+ bottom: 0;
292
+ left: 0;
293
+ position: fixed;
294
+ right: 0;
295
+ top: 0;
296
+ }
297
+
298
+ .modal__body {
299
+ background: white;
300
+ border-radius: var(--spacing-8);
301
+ border: 1px solid var(--color-neutral-600);
302
+ left: 50%;
303
+ padding: var(--spacing-4) var(--spacing-4);
304
+ position: absolute;
305
+ right: var(--spacing-16);
306
+ top: 50%;
307
+ transform: translate(-50%, -50%);
308
+ z-index: 5;
309
+ }
310
+
311
+ .modal__close {
312
+ position: absolute;
313
+ right: calc(var(--spacing-16) * -1);
314
+ top: calc(var(--spacing-16) * -1);
315
+ z-index: 5;
316
+ }
317
+
318
+ .modal__content {
319
+ border: 1px solid var(--color-neutral-100);
320
+ border-radius: var(--spacing-8);
321
+ display: flex;
322
+ flex-direction: column;
323
+ gap: var(--spacing-16);
324
+ padding: 0 var(--spacing-16);
325
+ }
326
+
327
+ .modal__footer {
328
+ padding-bottom: var(--spacing-16);
329
+ }
330
+ .loading {
331
+ align-items: center;
332
+ display: flex;
333
+ flex-direction: column;
334
+ height: 100%;
335
+ justify-content: center;;
336
+ position: relative;
337
+ }
package/dist/esm/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import clsx from 'clsx';
3
- import { useRef, useState, createContext, useEffect, useContext } from 'react';
3
+ import { useRef, useState, createContext, useEffect, useContext, useReducer } from 'react';
4
4
  import { TbArrowsDiagonal2 } from 'react-icons/tb';
5
+ import { IoClose } from 'react-icons/io5';
5
6
 
6
7
  const Anchor = ({ Custom, children, ...rest }) => Custom ? jsx(Custom, { ...rest, children: children }) : jsx("a", { ...rest, children: children });
7
8
  function Button({ children = "Click me", className = "", icon = undefined, isNewWindow = false, mode = "primary", size = "medium", as = "button", CustomAnchor, ...rest }) {
@@ -31,6 +32,14 @@ function TextArea({ className = "", disabled = true, hasToggleButton = true, hid
31
32
  }, 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" }) }))] }));
32
33
  }
33
34
 
35
+ function Modal({ modalref, children, title, subtitle, footer, hasCloseButton = true, handleClose, }) {
36
+ return (jsxs("div", { className: "modal", children: [jsx("div", { className: "modal__overlay" }), jsxs("div", { ref: modalref, className: "modal__body", children: [hasCloseButton && (jsx(Button, { mode: "secondary", className: "modal__close", size: "small", onClick: handleClose, children: jsx(IoClose, {}) })), jsxs("div", { className: "modal__content", children: [title && (jsxs("div", { className: "modal__header", children: [jsx("h3", { children: title }), jsx("h6", { children: subtitle })] })), jsx("div", { className: "modal__children", children: children }), footer && jsx("div", { className: "modal__footer", children: footer })] })] })] }));
37
+ }
38
+
39
+ function Loading({ img, children }) {
40
+ return (jsxs("div", { className: "loading", children: [jsx("img", { src: img ? img : "../../stories/assets/loading.gif" }), children] }));
41
+ }
42
+
34
43
  const ThemeContext = createContext(undefined);
35
44
  function ThemeProvider({ children }) {
36
45
  const [dataTheme, setDataTheme] = useState();
@@ -79,4 +88,125 @@ function useTheme({ dataTheme = undefined, paletteTheme = "water", } = {}) {
79
88
  return context;
80
89
  }
81
90
 
82
- export { Button, Input, TextArea, ThemeContext, ThemeProvider, useTheme };
91
+ const LoadingContext = createContext(undefined);
92
+ function loadingReducer(state, action) {
93
+ switch (action.type) {
94
+ case "set_ref": {
95
+ return { ...state, ref: action.ref };
96
+ }
97
+ case "start_loading": {
98
+ return { ...state, isLoading: true };
99
+ }
100
+ case "stop_loading": {
101
+ return { ...state, isLoading: false };
102
+ }
103
+ case "set_message": {
104
+ return { ...state, message: action.message };
105
+ }
106
+ default: {
107
+ throw new Error(`Unhandled action type: ${action.type}`);
108
+ }
109
+ }
110
+ }
111
+ function LoadingProvider({ children }) {
112
+ const [{ isLoading, message, ref }, dispatch] = useReducer(loadingReducer, {
113
+ isLoading: false,
114
+ message: "Loading",
115
+ ref: undefined,
116
+ });
117
+ const setRef = (ref) => {
118
+ dispatch({ type: "set_ref", ref });
119
+ };
120
+ const setMessage = (message) => {
121
+ dispatch({ type: "set_message", message });
122
+ };
123
+ const startLoading = () => {
124
+ dispatch({ type: "start_loading" });
125
+ };
126
+ const stopLoading = () => {
127
+ dispatch({ type: "stop_loading" });
128
+ };
129
+ return (jsxs(LoadingContext.Provider, { value: {
130
+ state: { ref, message, isLoading },
131
+ setMessage,
132
+ setRef,
133
+ startLoading,
134
+ stopLoading,
135
+ }, children: [!ref && jsx(Loading, { children: message }), children] }));
136
+ }
137
+ function useLoading({ ref, message } = {}) {
138
+ const context = useContext(LoadingContext);
139
+ // only happens if there is an initial mode value.
140
+ useEffect(() => {
141
+ ref && context?.setRef(ref);
142
+ message && context?.setMessage(message);
143
+ }, []);
144
+ if (context === undefined) {
145
+ throw new Error("useLoading must be used within a LoadingProvider");
146
+ }
147
+ return context;
148
+ }
149
+
150
+ const ModalContext = createContext(undefined);
151
+ function modalReducer(state, action) {
152
+ switch (action.type) {
153
+ case "open_modal": {
154
+ return { ...state, ...action.modal, isModal: true };
155
+ }
156
+ case "close_modal": {
157
+ return { ...state, isModal: false };
158
+ }
159
+ default: {
160
+ throw new Error(`Unhandled action type: ${action.type}`);
161
+ }
162
+ }
163
+ }
164
+ const defaultState = {
165
+ subtitle: undefined,
166
+ title: undefined,
167
+ content: undefined,
168
+ hasCloseButton: true,
169
+ footer: undefined,
170
+ };
171
+ function ModalProvider({ children }) {
172
+ const ref = useRef(null);
173
+ const [state, dispatch] = useReducer(modalReducer, {
174
+ isModal: false,
175
+ ...defaultState,
176
+ });
177
+ const openModal = (modal) => {
178
+ dispatch({ type: "open_modal", modal });
179
+ };
180
+ const closeModal = () => {
181
+ dispatch({ type: "close_modal" });
182
+ };
183
+ useEffect(() => {
184
+ if (state.isModal) {
185
+ const listener = (e) => {
186
+ if (state.isModal &&
187
+ ref.current &&
188
+ !ref.current.contains(e.target)) {
189
+ closeModal();
190
+ }
191
+ };
192
+ document.addEventListener("mousedown", listener);
193
+ return () => {
194
+ document.removeEventListener("mousedown", listener);
195
+ };
196
+ }
197
+ }, [closeModal]);
198
+ return (jsxs(ModalContext.Provider, { value: {
199
+ state,
200
+ openModal,
201
+ closeModal,
202
+ }, children: [children, state.isModal && (jsx(Modal, { modalref: ref, title: state.title, footer: state.footer, handleClose: closeModal, subtitle: state.subtitle, children: state.content }))] }));
203
+ }
204
+ function useModal({} = {}) {
205
+ const context = useContext(ModalContext);
206
+ if (context === undefined) {
207
+ throw new Error("useModal must be used within a ModalProvider");
208
+ }
209
+ return context;
210
+ }
211
+
212
+ export { Button, Input, Loading, LoadingContext, LoadingProvider, Modal, ModalContext, ModalProvider, TextArea, ThemeContext, ThemeProvider, useLoading, useModal, useTheme };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geoinsight/react-components",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "This library is the main UI component library for geoinsight",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",