@geoinsight/react-components 0.4.5 → 0.5.1

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.
@@ -79,7 +79,7 @@
79
79
  }
80
80
  }
81
81
 
82
- [palette-theme="water"] {
82
+ [data-palette="water"] {
83
83
  --color-primary-100: #d6efff;
84
84
  --color-primary-200: #ade0ff;
85
85
  --color-primary-300: #85d0ff;
@@ -91,7 +91,7 @@
91
91
  --color-primary-900: #00588f;
92
92
  }
93
93
 
94
- [palette-theme="earth"]{
94
+ [data-palette="earth"]{
95
95
  --color-primary-100: #f6e3cb;
96
96
  --color-primary-200: #edc897;
97
97
  --color-primary-300: #eabe86;
@@ -103,7 +103,7 @@
103
103
  --color-primary-900: #684312;
104
104
  }
105
105
 
106
- [palette-theme="forest"] {
106
+ [data-palette="forest"] {
107
107
  --color-primary-100: #bee8b0;
108
108
  --color-primary-200: #a4df90;
109
109
  --color-primary-300: #8ad671;
@@ -291,21 +291,39 @@ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic
291
291
  padding: var(--spacing-16);
292
292
  }
293
293
 
294
+ .form {
295
+ align-items: center;
296
+ display: flex;
297
+ flex-direction: column;
298
+ gap: var(--spacing-32);
299
+ padding: var(--spacing-32) 0;
300
+ }
301
+
302
+ .form__message {
303
+ align-items: center;
304
+ display: flex;
305
+ justify-content: center;
306
+ gap: var(--spacing-16);
307
+ }
294
308
  .input-group {
295
309
  display: flex;
296
310
  flex-direction: column;
297
311
  align-items: flex-start;
312
+ width: 100%;
298
313
  }
299
314
 
300
315
  .input {
316
+ box-sizing: border-box;
301
317
  background-color: var(--color-white);
302
318
  border-radius: var(--spacing-8);
303
319
  border: 2px solid var(--color-primary);
304
320
  color: var(--color-black);
305
321
  padding: var(--spacing-16) var(--spacing-24);
322
+ font-size:var(--font-size-16);
323
+ width: 100%;
306
324
  }
307
325
 
308
- .input:hover {
326
+ .input:enabled:hover {
309
327
  border: 3px solid var(--color-primary-700);
310
328
  }
311
329
 
@@ -314,18 +332,79 @@ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic
314
332
  outline: none;
315
333
  }
316
334
 
335
+ .input:disabled {
336
+ opacity: 0.5;
337
+ }
338
+
317
339
  .input--error {
318
340
  border: 3px solid var(--color-danger);
319
341
  }
320
342
 
343
+ .input--error:focus {
344
+ border: 3px solid var(--color-danger);
345
+ outline: none;
346
+ }
347
+
321
348
  .error {
322
349
  font-size: 12px;
323
350
  color: var(--color-danger);
324
351
  }
325
352
 
353
+ .loading {
354
+ align-items: center;
355
+ display: flex;
356
+ flex-direction: column;
357
+ height: 100%;
358
+ justify-content: center;;
359
+ position: relative;
360
+ }
361
+
362
+ .modal-overlay {
363
+ background: rgba(0, 0, 0, 0.3);
364
+ bottom: 0;
365
+ left: 0;
366
+ position: fixed;
367
+ right: 0;
368
+ top: 0;
369
+ }
370
+
371
+ .modal {
372
+ background: white;
373
+ border-radius: var(--spacing-8);
374
+ border: 1px solid var(--color-neutral-600);
375
+ color: var(--color-black);
376
+ left: 50%;
377
+ padding: var(--spacing-4) var(--spacing-4);
378
+ position: absolute;
379
+ right: var(--spacing-16);
380
+ top: 50%;
381
+ transform: translate(-50%, -50%);
382
+ z-index: 5;
383
+ }
384
+
385
+ .modal__close {
386
+ position: absolute;
387
+ right: calc(var(--spacing-16) * -1);
388
+ top: calc(var(--spacing-16) * -1);
389
+ z-index: 5;
390
+ }
391
+
392
+ .modal__content {
393
+ border: 1px solid var(--color-neutral-100);
394
+ border-radius: var(--spacing-8);
395
+ display: flex;
396
+ flex-direction: column;
397
+ gap: var(--spacing-16);
398
+ padding: 0 var(--spacing-16);
399
+ }
400
+
401
+ .modal__footer {
402
+ padding-bottom: var(--spacing-16);
403
+ }
326
404
  .textarea {
327
405
  margin-bottom: var(--spacing-8);
328
406
  position: relative;
407
+ width: 100%;
329
408
  }
330
409
 
331
410
  .textarea__input {
@@ -341,10 +420,14 @@ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic
341
420
  width: 100%;
342
421
  }
343
422
 
344
- .textarea__input:hover {
423
+ .textarea__input:enabled:hover {
345
424
  border: 3px solid var(--color-primary-700);
346
425
  }
347
426
 
427
+ .textarea__input:disabled {
428
+ opacity: 0.5;
429
+ }
430
+
348
431
  .textarea__button {
349
432
  background: var(--color-primary);
350
433
  border: 2px solid var(--color-secondary);
@@ -368,7 +451,7 @@ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic
368
451
  pointer-events: none;
369
452
  }
370
453
 
371
- .textarea__button:hover {
454
+ .textarea__button:enabled:hover {
372
455
  background: var(--color-secondary);
373
456
  color: var(--color-neutral-100);
374
457
  }
@@ -377,54 +460,3 @@ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic
377
460
  background: var(--color-primary-700);
378
461
  color: var(--color-neutral-100);
379
462
  }
380
-
381
- .modal-overlay {
382
- background: rgba(0, 0, 0, 0.3);
383
- bottom: 0;
384
- left: 0;
385
- position: fixed;
386
- right: 0;
387
- top: 0;
388
- }
389
-
390
- .modal {
391
- background: white;
392
- border-radius: var(--spacing-8);
393
- border: 1px solid var(--color-neutral-600);
394
- color: var(--color-black);
395
- left: 50%;
396
- padding: var(--spacing-4) var(--spacing-4);
397
- position: absolute;
398
- right: var(--spacing-16);
399
- top: 50%;
400
- transform: translate(-50%, -50%);
401
- z-index: 5;
402
- }
403
-
404
- .modal__close {
405
- position: absolute;
406
- right: calc(var(--spacing-16) * -1);
407
- top: calc(var(--spacing-16) * -1);
408
- z-index: 5;
409
- }
410
-
411
- .modal__content {
412
- border: 1px solid var(--color-neutral-100);
413
- border-radius: var(--spacing-8);
414
- display: flex;
415
- flex-direction: column;
416
- gap: var(--spacing-16);
417
- padding: 0 var(--spacing-16);
418
- }
419
-
420
- .modal__footer {
421
- padding-bottom: var(--spacing-16);
422
- }
423
- .loading {
424
- align-items: center;
425
- display: flex;
426
- flex-direction: column;
427
- height: 100%;
428
- justify-content: center;;
429
- position: relative;
430
- }
package/dist/cjs/index.js CHANGED
@@ -4,8 +4,10 @@ var jsxRuntime = require('react/jsx-runtime');
4
4
  var react = require('react');
5
5
  var clsx = require('clsx');
6
6
  var tfi = require('react-icons/tfi');
7
- var tb = require('react-icons/tb');
7
+ var bs = require('react-icons/bs');
8
+ var reactHookForm = require('react-hook-form');
8
9
  var io5 = require('react-icons/io5');
10
+ var tb = require('react-icons/tb');
9
11
 
10
12
  function recursiveChildren(children, i = 0) {
11
13
  return react.Children.map(children, (child, index) => {
@@ -99,9 +101,19 @@ function Button({ children = "Click me", className = "", icon = undefined, isNew
99
101
  }
100
102
 
101
103
  const ThemeContext = react.createContext(undefined);
102
- function ThemeProvider({ children }) {
104
+ function ThemeProvider({ children, dataTheme: dataThemeProp, dataPalette: dataPaletteProp = "water", }) {
103
105
  const [dataTheme, setDataTheme] = react.useState();
104
- const [paletteTheme, setPaletteTheme] = react.useState();
106
+ const [dataPalette, setDataPalette] = react.useState();
107
+ react.useEffect(() => {
108
+ if (dataPaletteProp) {
109
+ switchDataPalette(dataPaletteProp);
110
+ }
111
+ }, [dataPaletteProp]);
112
+ react.useEffect(() => {
113
+ if (dataThemeProp) {
114
+ switchDataTheme(dataThemeProp);
115
+ }
116
+ }, [dataThemeProp]);
105
117
  react.useEffect(() => {
106
118
  if (window.matchMedia) {
107
119
  if (localStorage.getItem("data-theme")) {
@@ -119,27 +131,15 @@ function ThemeProvider({ children }) {
119
131
  setDataTheme(mode);
120
132
  localStorage.setItem("data-theme", mode);
121
133
  };
122
- const switchPaletteTheme = (mode) => {
123
- document.documentElement.setAttribute("palette-theme", mode);
124
- setPaletteTheme(mode);
134
+ const switchDataPalette = (mode) => {
135
+ document.documentElement.setAttribute("data-palette", mode);
136
+ setDataPalette(mode);
125
137
  localStorage.setItem("palette-theme", mode);
126
138
  };
127
- return (jsxRuntime.jsx(ThemeContext.Provider, { value: { dataTheme, switchDataTheme, paletteTheme, switchPaletteTheme }, children: children }));
139
+ return (jsxRuntime.jsx(ThemeContext.Provider, { value: { dataTheme, switchDataTheme, dataPalette, switchDataPalette }, children: children }));
128
140
  }
129
- function useTheme({ dataTheme = undefined, paletteTheme = "water", } = {}) {
141
+ function useTheme() {
130
142
  const context = react.useContext(ThemeContext);
131
- // only happens if there is an initial mode value.
132
- react.useEffect(() => {
133
- if (dataTheme && !localStorage.getItem("data-theme")) {
134
- context?.switchDataTheme(dataTheme);
135
- }
136
- else if (!dataTheme && localStorage.getItem("data-theme")) {
137
- localStorage.removeItem("data-theme");
138
- }
139
- }, []);
140
- react.useEffect(() => {
141
- context?.switchPaletteTheme(paletteTheme);
142
- }, []);
143
143
  if (context === undefined) {
144
144
  throw new Error("useTheme must be used within a ThemeProvider");
145
145
  }
@@ -179,11 +179,49 @@ const AccordionContent = function AccordionContent({ children, label, toggle, })
179
179
  toggle[label].isToggle && (jsxRuntime.jsx("div", { className: "accordion-content", children: children })));
180
180
  };
181
181
 
182
- function Input({ className = "", classNameGroup = "", errorMessage = "", inputRef, styleGroup, ...rest }) {
183
- return (jsxRuntime.jsxs("div", { className: `input-group ${classNameGroup}`, style: styleGroup, children: [jsxRuntime.jsx("input", { ref: inputRef, className: `input ${errorMessage ? "input--error" : ""} ${className}`, ...rest }), errorMessage && jsxRuntime.jsx("span", { className: "error", children: errorMessage })] }));
182
+ function Form({ children, onSubmit, submitButton = {
183
+ label: "Submit",
184
+ }, ...rest }) {
185
+ const { handleSubmit, control, formState: { errors, isValid }, } = reactHookForm.useForm();
186
+ const [result, setResult] = react.useState({
187
+ message: "",
188
+ isSuccess: false,
189
+ });
190
+ return (jsxRuntime.jsxs("form", { className: "form", onSubmit: handleSubmit(async (data) => await onSubmit(data, setResult)), ...rest, children: [react.Children.map(children, (child) => {
191
+ const { props: { name, error, isRequired, ...rest }, } = child;
192
+ return (jsxRuntime.jsx(reactHookForm.Controller, { name: name, control: control, rules: {
193
+ ...(isRequired ? {
194
+ required: error?.message || "Field is required",
195
+ } : {}),
196
+ }, render: ({ field }) => react.cloneElement(child, {
197
+ error: {
198
+ is: Object.keys(errors).length > 0 && !!errors[name],
199
+ message: errors &&
200
+ Object.keys(errors).length > 0 &&
201
+ errors[name]?.message,
202
+ },
203
+ ...field,
204
+ ...rest,
205
+ }) }));
206
+ }), result.message && (jsxRuntime.jsxs("div", { className: "form__message", children: [result.isSuccess ? (jsxRuntime.jsx(bs.BsCheckCircleFill, { color: "var(--color-success)", size: 48 })) : (jsxRuntime.jsx(bs.BsXCircleFill, { color: "var(--color-danger)", size: 48 })), result.message] })), jsxRuntime.jsx(Button, { type: "submit", disabled: !isValid, children: submitButton.label })] }));
207
+ }
208
+
209
+ function Input({ className = "", classNameGroup = "", error = {
210
+ is: false,
211
+ message: "",
212
+ }, inputRef, styleGroup, placeholder = "Insert value", isRequired, ...rest }) {
213
+ return (jsxRuntime.jsxs("div", { className: clsx("input-group", classNameGroup), style: styleGroup, children: [jsxRuntime.jsx("input", { ref: inputRef, className: clsx("input", error.is ? "input--error" : "", className), placeholder: placeholder, ...rest }), error && error.is && jsxRuntime.jsx("span", { className: "error", children: error.message })] }));
184
214
  }
185
215
 
186
- function TextArea({ className = "", disabled = true, hasToggleButton = true, hideHeight = "5rem", placeholder = "", showHeight = "10rem", style = {}, textareaClassName = "", ...rest }) {
216
+ function Loading({ img, children }) {
217
+ return (jsxRuntime.jsxs("div", { className: "loading", children: [jsxRuntime.jsx("img", { src: img ? img : "../../stories/assets/loading.gif" }), children] }));
218
+ }
219
+
220
+ function Modal({ modalref, children, title, subtitle, footer, hasCloseButton = true, handleClose, }) {
221
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "modal-overlay" }), jsxRuntime.jsxs("div", { ref: modalref, className: "modal", 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 })] })] })] }));
222
+ }
223
+
224
+ function TextArea({ className = "", disabled = true, hasToggleButton = true, hideHeight = "5rem", placeholder = "Insert value", showHeight = "10rem", style = {}, textareaClassName = "", ...rest }) {
187
225
  const ref = react.useRef();
188
226
  const [isShow, setIsShow] = react.useState(false);
189
227
  const handleClickToggle = () => {
@@ -199,15 +237,7 @@ function TextArea({ className = "", disabled = true, hasToggleButton = true, hid
199
237
  };
200
238
  return (jsxRuntime.jsxs("div", { className: clsx("textarea", className), style: style, children: [jsxRuntime.jsx("textarea", { ref: ref, className: clsx("textarea__input", textareaClassName), style: {
201
239
  height: hasToggleButton ? hideHeight : showHeight,
202
- }, 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" }) }))] }));
203
- }
204
-
205
- function Modal({ modalref, children, title, subtitle, footer, hasCloseButton = true, handleClose, }) {
206
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "modal-overlay" }), jsxRuntime.jsxs("div", { ref: modalref, className: "modal", 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 })] })] })] }));
207
- }
208
-
209
- function Loading({ img, children }) {
210
- return (jsxRuntime.jsxs("div", { className: "loading", children: [jsxRuntime.jsx("img", { src: img ? img : "../../stories/assets/loading.gif" }), children] }));
240
+ }, placeholder: placeholder, disabled: disabled, ...rest }), hasToggleButton && (jsxRuntime.jsx("button", { type: "button", className: clsx("textarea__button", isShow && "textarea__button--show"), onClick: handleClickToggle, disabled: disabled, children: jsxRuntime.jsx(tb.TbArrowsDiagonal2, { size: "1.5rem" }) }))] }));
211
241
  }
212
242
 
213
243
  const LoadingContext = react.createContext(undefined);
@@ -336,6 +366,7 @@ exports.AccordionButton = AccordionButton;
336
366
  exports.AccordionContent = AccordionContent;
337
367
  exports.AccordionItem = AccordionItem;
338
368
  exports.Button = Button;
369
+ exports.Form = Form;
339
370
  exports.Input = Input;
340
371
  exports.Loading = Loading;
341
372
  exports.LoadingContext = LoadingContext;
@@ -79,7 +79,7 @@
79
79
  }
80
80
  }
81
81
 
82
- [palette-theme="water"] {
82
+ [data-palette="water"] {
83
83
  --color-primary-100: #d6efff;
84
84
  --color-primary-200: #ade0ff;
85
85
  --color-primary-300: #85d0ff;
@@ -91,7 +91,7 @@
91
91
  --color-primary-900: #00588f;
92
92
  }
93
93
 
94
- [palette-theme="earth"]{
94
+ [data-palette="earth"]{
95
95
  --color-primary-100: #f6e3cb;
96
96
  --color-primary-200: #edc897;
97
97
  --color-primary-300: #eabe86;
@@ -103,7 +103,7 @@
103
103
  --color-primary-900: #684312;
104
104
  }
105
105
 
106
- [palette-theme="forest"] {
106
+ [data-palette="forest"] {
107
107
  --color-primary-100: #bee8b0;
108
108
  --color-primary-200: #a4df90;
109
109
  --color-primary-300: #8ad671;
@@ -291,21 +291,39 @@ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic
291
291
  padding: var(--spacing-16);
292
292
  }
293
293
 
294
+ .form {
295
+ align-items: center;
296
+ display: flex;
297
+ flex-direction: column;
298
+ gap: var(--spacing-32);
299
+ padding: var(--spacing-32) 0;
300
+ }
301
+
302
+ .form__message {
303
+ align-items: center;
304
+ display: flex;
305
+ justify-content: center;
306
+ gap: var(--spacing-16);
307
+ }
294
308
  .input-group {
295
309
  display: flex;
296
310
  flex-direction: column;
297
311
  align-items: flex-start;
312
+ width: 100%;
298
313
  }
299
314
 
300
315
  .input {
316
+ box-sizing: border-box;
301
317
  background-color: var(--color-white);
302
318
  border-radius: var(--spacing-8);
303
319
  border: 2px solid var(--color-primary);
304
320
  color: var(--color-black);
305
321
  padding: var(--spacing-16) var(--spacing-24);
322
+ font-size:var(--font-size-16);
323
+ width: 100%;
306
324
  }
307
325
 
308
- .input:hover {
326
+ .input:enabled:hover {
309
327
  border: 3px solid var(--color-primary-700);
310
328
  }
311
329
 
@@ -314,18 +332,79 @@ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic
314
332
  outline: none;
315
333
  }
316
334
 
335
+ .input:disabled {
336
+ opacity: 0.5;
337
+ }
338
+
317
339
  .input--error {
318
340
  border: 3px solid var(--color-danger);
319
341
  }
320
342
 
343
+ .input--error:focus {
344
+ border: 3px solid var(--color-danger);
345
+ outline: none;
346
+ }
347
+
321
348
  .error {
322
349
  font-size: 12px;
323
350
  color: var(--color-danger);
324
351
  }
325
352
 
353
+ .loading {
354
+ align-items: center;
355
+ display: flex;
356
+ flex-direction: column;
357
+ height: 100%;
358
+ justify-content: center;;
359
+ position: relative;
360
+ }
361
+
362
+ .modal-overlay {
363
+ background: rgba(0, 0, 0, 0.3);
364
+ bottom: 0;
365
+ left: 0;
366
+ position: fixed;
367
+ right: 0;
368
+ top: 0;
369
+ }
370
+
371
+ .modal {
372
+ background: white;
373
+ border-radius: var(--spacing-8);
374
+ border: 1px solid var(--color-neutral-600);
375
+ color: var(--color-black);
376
+ left: 50%;
377
+ padding: var(--spacing-4) var(--spacing-4);
378
+ position: absolute;
379
+ right: var(--spacing-16);
380
+ top: 50%;
381
+ transform: translate(-50%, -50%);
382
+ z-index: 5;
383
+ }
384
+
385
+ .modal__close {
386
+ position: absolute;
387
+ right: calc(var(--spacing-16) * -1);
388
+ top: calc(var(--spacing-16) * -1);
389
+ z-index: 5;
390
+ }
391
+
392
+ .modal__content {
393
+ border: 1px solid var(--color-neutral-100);
394
+ border-radius: var(--spacing-8);
395
+ display: flex;
396
+ flex-direction: column;
397
+ gap: var(--spacing-16);
398
+ padding: 0 var(--spacing-16);
399
+ }
400
+
401
+ .modal__footer {
402
+ padding-bottom: var(--spacing-16);
403
+ }
326
404
  .textarea {
327
405
  margin-bottom: var(--spacing-8);
328
406
  position: relative;
407
+ width: 100%;
329
408
  }
330
409
 
331
410
  .textarea__input {
@@ -341,10 +420,14 @@ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic
341
420
  width: 100%;
342
421
  }
343
422
 
344
- .textarea__input:hover {
423
+ .textarea__input:enabled:hover {
345
424
  border: 3px solid var(--color-primary-700);
346
425
  }
347
426
 
427
+ .textarea__input:disabled {
428
+ opacity: 0.5;
429
+ }
430
+
348
431
  .textarea__button {
349
432
  background: var(--color-primary);
350
433
  border: 2px solid var(--color-secondary);
@@ -368,7 +451,7 @@ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic
368
451
  pointer-events: none;
369
452
  }
370
453
 
371
- .textarea__button:hover {
454
+ .textarea__button:enabled:hover {
372
455
  background: var(--color-secondary);
373
456
  color: var(--color-neutral-100);
374
457
  }
@@ -377,54 +460,3 @@ transition: var(--transition-bg-cubic-bezier), var(--transition-box-shadow-cubic
377
460
  background: var(--color-primary-700);
378
461
  color: var(--color-neutral-100);
379
462
  }
380
-
381
- .modal-overlay {
382
- background: rgba(0, 0, 0, 0.3);
383
- bottom: 0;
384
- left: 0;
385
- position: fixed;
386
- right: 0;
387
- top: 0;
388
- }
389
-
390
- .modal {
391
- background: white;
392
- border-radius: var(--spacing-8);
393
- border: 1px solid var(--color-neutral-600);
394
- color: var(--color-black);
395
- left: 50%;
396
- padding: var(--spacing-4) var(--spacing-4);
397
- position: absolute;
398
- right: var(--spacing-16);
399
- top: 50%;
400
- transform: translate(-50%, -50%);
401
- z-index: 5;
402
- }
403
-
404
- .modal__close {
405
- position: absolute;
406
- right: calc(var(--spacing-16) * -1);
407
- top: calc(var(--spacing-16) * -1);
408
- z-index: 5;
409
- }
410
-
411
- .modal__content {
412
- border: 1px solid var(--color-neutral-100);
413
- border-radius: var(--spacing-8);
414
- display: flex;
415
- flex-direction: column;
416
- gap: var(--spacing-16);
417
- padding: 0 var(--spacing-16);
418
- }
419
-
420
- .modal__footer {
421
- padding-bottom: var(--spacing-16);
422
- }
423
- .loading {
424
- align-items: center;
425
- display: flex;
426
- flex-direction: column;
427
- height: 100%;
428
- justify-content: center;;
429
- position: relative;
430
- }
package/dist/esm/index.js CHANGED
@@ -2,8 +2,10 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { Children, isValidElement, cloneElement, createContext, useState, useContext, useEffect, useRef, useReducer } from 'react';
3
3
  import clsx from 'clsx';
4
4
  import { TfiAngleDown, TfiAngleUp } from 'react-icons/tfi';
5
- import { TbArrowsDiagonal2 } from 'react-icons/tb';
5
+ import { BsCheckCircleFill, BsXCircleFill } from 'react-icons/bs';
6
+ import { useForm, Controller } from 'react-hook-form';
6
7
  import { IoClose } from 'react-icons/io5';
8
+ import { TbArrowsDiagonal2 } from 'react-icons/tb';
7
9
 
8
10
  function recursiveChildren(children, i = 0) {
9
11
  return Children.map(children, (child, index) => {
@@ -97,9 +99,19 @@ function Button({ children = "Click me", className = "", icon = undefined, isNew
97
99
  }
98
100
 
99
101
  const ThemeContext = createContext(undefined);
100
- function ThemeProvider({ children }) {
102
+ function ThemeProvider({ children, dataTheme: dataThemeProp, dataPalette: dataPaletteProp = "water", }) {
101
103
  const [dataTheme, setDataTheme] = useState();
102
- const [paletteTheme, setPaletteTheme] = useState();
104
+ const [dataPalette, setDataPalette] = useState();
105
+ useEffect(() => {
106
+ if (dataPaletteProp) {
107
+ switchDataPalette(dataPaletteProp);
108
+ }
109
+ }, [dataPaletteProp]);
110
+ useEffect(() => {
111
+ if (dataThemeProp) {
112
+ switchDataTheme(dataThemeProp);
113
+ }
114
+ }, [dataThemeProp]);
103
115
  useEffect(() => {
104
116
  if (window.matchMedia) {
105
117
  if (localStorage.getItem("data-theme")) {
@@ -117,27 +129,15 @@ function ThemeProvider({ children }) {
117
129
  setDataTheme(mode);
118
130
  localStorage.setItem("data-theme", mode);
119
131
  };
120
- const switchPaletteTheme = (mode) => {
121
- document.documentElement.setAttribute("palette-theme", mode);
122
- setPaletteTheme(mode);
132
+ const switchDataPalette = (mode) => {
133
+ document.documentElement.setAttribute("data-palette", mode);
134
+ setDataPalette(mode);
123
135
  localStorage.setItem("palette-theme", mode);
124
136
  };
125
- return (jsx(ThemeContext.Provider, { value: { dataTheme, switchDataTheme, paletteTheme, switchPaletteTheme }, children: children }));
137
+ return (jsx(ThemeContext.Provider, { value: { dataTheme, switchDataTheme, dataPalette, switchDataPalette }, children: children }));
126
138
  }
127
- function useTheme({ dataTheme = undefined, paletteTheme = "water", } = {}) {
139
+ function useTheme() {
128
140
  const context = useContext(ThemeContext);
129
- // only happens if there is an initial mode value.
130
- useEffect(() => {
131
- if (dataTheme && !localStorage.getItem("data-theme")) {
132
- context?.switchDataTheme(dataTheme);
133
- }
134
- else if (!dataTheme && localStorage.getItem("data-theme")) {
135
- localStorage.removeItem("data-theme");
136
- }
137
- }, []);
138
- useEffect(() => {
139
- context?.switchPaletteTheme(paletteTheme);
140
- }, []);
141
141
  if (context === undefined) {
142
142
  throw new Error("useTheme must be used within a ThemeProvider");
143
143
  }
@@ -177,11 +177,49 @@ const AccordionContent = function AccordionContent({ children, label, toggle, })
177
177
  toggle[label].isToggle && (jsx("div", { className: "accordion-content", children: children })));
178
178
  };
179
179
 
180
- function Input({ className = "", classNameGroup = "", errorMessage = "", inputRef, styleGroup, ...rest }) {
181
- return (jsxs("div", { className: `input-group ${classNameGroup}`, style: styleGroup, children: [jsx("input", { ref: inputRef, className: `input ${errorMessage ? "input--error" : ""} ${className}`, ...rest }), errorMessage && jsx("span", { className: "error", children: errorMessage })] }));
180
+ function Form({ children, onSubmit, submitButton = {
181
+ label: "Submit",
182
+ }, ...rest }) {
183
+ const { handleSubmit, control, formState: { errors, isValid }, } = useForm();
184
+ const [result, setResult] = useState({
185
+ message: "",
186
+ isSuccess: false,
187
+ });
188
+ return (jsxs("form", { className: "form", onSubmit: handleSubmit(async (data) => await onSubmit(data, setResult)), ...rest, children: [Children.map(children, (child) => {
189
+ const { props: { name, error, isRequired, ...rest }, } = child;
190
+ return (jsx(Controller, { name: name, control: control, rules: {
191
+ ...(isRequired ? {
192
+ required: error?.message || "Field is required",
193
+ } : {}),
194
+ }, render: ({ field }) => cloneElement(child, {
195
+ error: {
196
+ is: Object.keys(errors).length > 0 && !!errors[name],
197
+ message: errors &&
198
+ Object.keys(errors).length > 0 &&
199
+ errors[name]?.message,
200
+ },
201
+ ...field,
202
+ ...rest,
203
+ }) }));
204
+ }), result.message && (jsxs("div", { className: "form__message", children: [result.isSuccess ? (jsx(BsCheckCircleFill, { color: "var(--color-success)", size: 48 })) : (jsx(BsXCircleFill, { color: "var(--color-danger)", size: 48 })), result.message] })), jsx(Button, { type: "submit", disabled: !isValid, children: submitButton.label })] }));
205
+ }
206
+
207
+ function Input({ className = "", classNameGroup = "", error = {
208
+ is: false,
209
+ message: "",
210
+ }, inputRef, styleGroup, placeholder = "Insert value", isRequired, ...rest }) {
211
+ return (jsxs("div", { className: clsx("input-group", classNameGroup), style: styleGroup, children: [jsx("input", { ref: inputRef, className: clsx("input", error.is ? "input--error" : "", className), placeholder: placeholder, ...rest }), error && error.is && jsx("span", { className: "error", children: error.message })] }));
182
212
  }
183
213
 
184
- function TextArea({ className = "", disabled = true, hasToggleButton = true, hideHeight = "5rem", placeholder = "", showHeight = "10rem", style = {}, textareaClassName = "", ...rest }) {
214
+ function Loading({ img, children }) {
215
+ return (jsxs("div", { className: "loading", children: [jsx("img", { src: img ? img : "../../stories/assets/loading.gif" }), children] }));
216
+ }
217
+
218
+ function Modal({ modalref, children, title, subtitle, footer, hasCloseButton = true, handleClose, }) {
219
+ return (jsxs(Fragment, { children: [jsx("div", { className: "modal-overlay" }), jsxs("div", { ref: modalref, className: "modal", 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 })] })] })] }));
220
+ }
221
+
222
+ function TextArea({ className = "", disabled = true, hasToggleButton = true, hideHeight = "5rem", placeholder = "Insert value", showHeight = "10rem", style = {}, textareaClassName = "", ...rest }) {
185
223
  const ref = useRef();
186
224
  const [isShow, setIsShow] = useState(false);
187
225
  const handleClickToggle = () => {
@@ -197,15 +235,7 @@ function TextArea({ className = "", disabled = true, hasToggleButton = true, hid
197
235
  };
198
236
  return (jsxs("div", { className: clsx("textarea", className), style: style, children: [jsx("textarea", { ref: ref, className: clsx("textarea__input", textareaClassName), style: {
199
237
  height: hasToggleButton ? hideHeight : showHeight,
200
- }, 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" }) }))] }));
201
- }
202
-
203
- function Modal({ modalref, children, title, subtitle, footer, hasCloseButton = true, handleClose, }) {
204
- return (jsxs(Fragment, { children: [jsx("div", { className: "modal-overlay" }), jsxs("div", { ref: modalref, className: "modal", 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 })] })] })] }));
205
- }
206
-
207
- function Loading({ img, children }) {
208
- return (jsxs("div", { className: "loading", children: [jsx("img", { src: img ? img : "../../stories/assets/loading.gif" }), children] }));
238
+ }, placeholder: placeholder, disabled: disabled, ...rest }), hasToggleButton && (jsx("button", { type: "button", className: clsx("textarea__button", isShow && "textarea__button--show"), onClick: handleClickToggle, disabled: disabled, children: jsx(TbArrowsDiagonal2, { size: "1.5rem" }) }))] }));
209
239
  }
210
240
 
211
241
  const LoadingContext = createContext(undefined);
@@ -329,4 +359,4 @@ function useModal({} = {}) {
329
359
  return context;
330
360
  }
331
361
 
332
- export { Accordion, AccordionButton, AccordionContent, AccordionItem, Button, Input, Loading, LoadingContext, LoadingProvider, Modal, ModalContext, ModalProvider, TextArea, ThemeContext, ThemeProvider, useLoading, useModal, useTheme };
362
+ export { Accordion, AccordionButton, AccordionContent, AccordionItem, Button, Form, 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.4.5",
3
+ "version": "0.5.1",
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",
@@ -18,6 +18,7 @@
18
18
  "clsx": "^1.2.1",
19
19
  "react": "^18.2.0",
20
20
  "react-dom": "^18.2.0",
21
+ "react-hook-form": "^7.45.2",
21
22
  "react-icons": "^4.7.1",
22
23
  "typescript": "^4.9.4"
23
24
  },